Как взять только определенные значения из JSON? Swift 4 - PullRequest
0 голосов
/ 03 июля 2018

Я делал приложение погоды, которое может отображать температуры в «день» и «ночь». Для этого мне нужно взять данные из API, приведенного ниже.

здесь

Если вы проверили это, проблема в том, что мне нужно брать только температуры из времен «3:00 AM» и «15:00» / «3:00 PM», игнорируя другие времена и температуры. Затем я должен отобразить его на моем UICollectionView (сделаю это сам)

Я знаю, что это можно сделать, используя DateFormatter и принимая значение из "dt" или "dt_txt". Однако мне действительно нужно знать, как это можно сделать. Источник будет прикреплен. Любая помощь будет оценена. Любые ошибки, которые вы заметите, кроме моей проблемы, также будут оценены. :]

ViewController: ПРИМЕЧАНИЕ: пожалуйста, смотрите только функции UICollectionView, я добавил другие только для справки

class SecondTaskVC: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {

    var weatherModel: WeatherModelDecodable?
    let weatherMmodel = [WeatherModelDecodable]()
    var listModel = [ListDecodable]()

    let textArray = ["понедельник", "вторник", "среда", "четверг", "пятница", "суббота", "воскресенье"]


    @IBOutlet weak var tempLabel: UILabel!

    @IBOutlet weak var cityLabel: UILabel!

    @IBOutlet weak var descrpLabel: UILabel!

    @IBOutlet weak var dateLabel: UILabel!

    override func viewDidLoad() {

        self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())


    }

    // UICollectionView

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return textArray.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "WeatherCollectionViewCell", for: indexPath) as! WeatherCollectionViewCell

        let urlString = "https://api.openweathermap.org/data/2.5/forecast?lat=42.874722&lon=74.612222&APPID=079587841f01c6b277a82c1c7788a6c3"
        let url = URL(string: urlString)
        Alamofire.request(url!).responseJSON { (response) in
            let result = response.data
            do{
                let decoder = JSONDecoder()
                self.weatherModel = try decoder.decode(WeatherModelDecodable.self, from: result!)
                if let tempToConvert = self.weatherModel?.list[indexPath.row].main.temp{

                    // CHECK THIS, I KNOW IT IS NOT CORRECT, BUT YOU GET ME.
                    if let timeResult = (self.weatherModel?.list[indexPath.row].dt) {
                        let dateFormatter = DateFormatter()
                        dateFormatter.dateStyle = .none
                        dateFormatter.timeStyle = .short

                        let date = Date(timeIntervalSince1970: Double(timeResult))
                        if dateFormatter.string(from: date) == "3:00 AM"{
                            cell.dayTemp.text = String(format: "%.0f", tempToConvert - 273.15) + "°C"
                            self.tempLabel.text = String(format: "%.0f", tempToConvert - 273.15) + "°C"
                    }
                        if dateFormatter.string(from: date) == "3:00 PM"{
                            cell.dayTemp.text = "4 c"
                            //self.tempLabel.text = String(format: "%.0f", tempToConvert - 273.15) + "°C"
                        }
                    }
                    ///////
                }
                self.cityLabel.text = self.weatherModel?.city.name
                self.dateLabel.text = self.weatherModel?.list[indexPath.row].dtTxt

                // displaying date and the week
            if  let dateResult = (self.weatherModel?.list[indexPath.row].dt) {
                let date = Date(timeIntervalSince1970: TimeInterval(dateResult))
                let dateFormatter = DateFormatter()
                dateFormatter.timeStyle = DateFormatter.Style.medium //Set time style
                dateFormatter.dateStyle = DateFormatter.Style.medium //Set date style
                let localDate = dateFormatter.string(from: date)
                let str = localDate.components(separatedBy: " 2018")
                let dd = localDate.replacingOccurrences(of: str[0], with: self.textArray[indexPath.row])
                let stringg = dd.components(separatedBy: " ")
                cell.dayCollection.text = stringg[0]
                print(stringg[0])
            }
        }catch let error{
            print("error in decoding",error.localizedDescription)
        }
    }
    return cell
}
 }

Модель данных: В случае, если это важно

struct WeatherModelDecodable: Codable {
    let list: [ListDecodable]
    let city: CityDecodable
    enum CodinKeys: String, CodingKey{
        case list = "list"
        case city = "city"
    }
}

struct CityDecodable: Codable {
    let name: String
}
struct ListDecodable: Codable {
    let dt: Int
    let main: MainClassDecodable
    let weather: [WeatherDecodable]
    let wind: WindDecodable
    let dtTxt: String

enum CodingKeys: String, CodingKey{
    case dt = "dt"
    case main = "main"
    case weather = "weather"
    case wind = "wind"
    case dtTxt = "dt_txt"
}

 }
struct MainClassDecodable: Codable {
     let temp: Double
     let tempMin: Double
     let tempMax: Double
     let pressure: Double
     let humidity: Int

enum CodingKeys: String, CodingKey {
    case temp = "temp"
    case tempMin = "temp_min"
    case tempMax = "temp_max"
    case pressure = "pressure"
    case humidity = "humidity"
    }
}
struct WeatherDecodable: Codable {
     let main: String
     let description: String

enum CodingKeys: String, CodingKey {
    case main = "main"
    case description = "description"
}
}
struct WindDecodable: Codable {
     let speed: Double
     let deg: Double
}

Если вам нужно что-нибудь, что поможет мне решить эту проблему, пожалуйста, не стесняйтесь спрашивать.

1 Ответ

0 голосов
/ 03 июля 2018
  • Прежде всего, если вы вставите &units=metric в URL-запрос, вы получите градусы в °C (преобразование не требуется).
  • Во-вторых, если вы используете стратегию декодирования даты .secondsSince1970, вы можете декодировать dt как Date (преобразование не требуется).
  • В-третьих, если вы используете стратегию декодирования ключа .convertFromSnakeCase, вы можете опустить все CodingKeys.

Это упрощенная версия ваших структур, в которой пропущены избыточные вхождения Decodable в именах, dt будет декодироваться как Date

struct WeatherModel : Decodable {
    let cod : String
    let list : [List]
}

struct List : Decodable {
    let weather : [Weather]
    let main : Main
    let dt : Date
}

struct Weather : Decodable {
    let main : String
    let description : String
}

struct Main: Decodable {
    let temp : Double
    let tempMin : Double
    let tempMax : Double
    let pressure : Double
    let humidity : Int
}

Расшифруйте JSON с помощью упомянутых стратегий

do {
     let decoder = JSONDecoder()
     decoder.keyDecodingStrategy = .convertFromSnakeCase
     decoder.dateDecodingStrategy = .secondsSince1970
     self.weatherModel = try decoder.decode(WeatherModel.self, from: result!)

Чтобы отфильтровать даты 3:00 / 15:00, вам необходимо сначала указать разницу между местным временем и UTC

     let utcDifference = TimeZone.current.secondsFromGMT() / 3600

Теперь отфильтруйте массив list

.
     let threeAMPMForecast = self.weatherModel.list.filter{
         let hour = Calendar.current.component(.hour, from: $0.dt)
         return hour == (3 + utcDifference) || hour == (15 + utcDifference)
     }
     print(threeAMPMForecast)
     // or to print all temperatures
     print(threeAMPMForecast.map{ $0.main.temp }) 

} catch {
    print(error)
}

Пожалуйста, попробуйте код на игровой площадке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...