Почему JSON возвращается как ноль для всего, кроме широты и долготы?

import UIKit

class ViewController: UIViewController {

@IBOutlet weak var tableview: UITableView!
var weatherList: [weatherJSON] = []


func downloadJSON() {
    let jsonUrlString = "https://api.darksky.net/forecast/59c6b6b7efd5c3fc0f617338cfae6c48/40.7127,-74.0059"
    guard let url = URL(string: jsonUrlString) else {return}
    URLSession.shared.dataTask(with: url) { (data, response, err) in
        guard let data = data else {return}

        do {
            let JSON = try JSONDecoder().decode(weatherJSON.self, from: data)
            self.weatherList.append(JSON)
            print(self.weatherList)
            DispatchQueue.main.async {
                self.tableview.reloadData()
            }
        } catch let jsonErr {
            print("Error serializing json", jsonErr)
        }

        }.resume()
}

override func viewDidLoad() {
    super.viewDidLoad()
    downloadJSON()

}
}


extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return weatherList.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! countryCell


cell.nameLabel?.text = "\(String(describing: weatherList[indexPath.row].latitude))"


    return cell
}
}

extension ViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    performSegue(withIdentifier: "segue1", sender: nil)
}
}

Изменить: я успешно вызвал данные JSON, используя интерполяцию строк -

cell.nameLabel?.text = "(Строка (описывающая: WeatherList[indexPath.row].широта))"

но теперь единственная информация, возвращающая в моем вызове что-либо, кроме нуля, - это широта и долгота. Почему единственное, что возвращается из моего вызова JSON, успешно равно нулю? Я что-то неправильно называю? Спасибо за вашу помощь. Если я должен сделать новый пост, пожалуйста, дайте мне знать. Я думаю, что это на ту же тему, поскольку это почти та же идея, что и исходная публикация, написанная мной вчера.

Сам Stackoverflow не позволит мне опубликовать сообщение, не добавив больше текста, но, поскольку я уже сказал все, что мне нужно было сказать, это просто наполнитель.


person Westopher    schedule 25.02.2019    source источник
comment
Где ваша попытка обновить свойство weatherList загруженными данными?   -  person rmaddy    schedule 26.02.2019
comment
(Я новичок, поэтому я знаю, что задаю очень простой вопрос, но я не знаю, как это сделать.) Как бы это сделать?   -  person Westopher    schedule 26.02.2019
comment
Вы не сохраняете результат JSON запроса в WeatherList[]. Вам нужно сделать это. Я объясняю в своем ответе @Westopher   -  person Gabo Ruiz    schedule 26.02.2019
comment
Это все равно не может работать. JSON — это отдельный объект, а weatherList вы объявили как массив. Ответ зависит от структуры структуры weatherJSON. И какую информацию — их много — вы хотите отобразить? Кстати, имена структур должны начинаться с заглавной буквы.   -  person vadian    schedule 26.02.2019
comment
@vadian Я буквально просто хочу получить любую информацию, которую смогу, из анализа этого json в моем представлении таблицы. Да, в моей модели мои структуры пишутся с большой буквы; Я обновлю это в своем коде, спасибо. Как бы вы тогда правильно добавили json в список погоды? Как выглядит этот код?   -  person Westopher    schedule 26.02.2019
comment
Ошибку cannot assign легко исправить, просто создайте строку из результата: String(weatherList[indexPath.row].currently!.cloudCover). Вы должны объявить currently необязательным, чтобы избежать принудительного развертывания. Но у вас все еще есть проблема, заключающаяся в том, что ваш массив источников данных содержит только один элемент, потому что корневым объектом JSON погоды является словарь.   -  person vadian    schedule 26.02.2019
comment
Это была и моя первая мысль! Великие умы. Но я делаю это и получаю эту ошибку: Невозможно вызвать инициализатор для типа «String» со списком аргументов типа «(Float?)»: -/   -  person Westopher    schedule 26.02.2019
comment
О, cloudCover тоже необязательно. String(weatherList[indexPath.row].currently!.cloudCover!). API-интерфейсы погоды отправляют надежные данные, объявляя свойства необязательными, насколько это возможно.   -  person vadian    schedule 26.02.2019
comment
Когда я делаю JSON массивом, это дает мне эту ошибку: Невозможно преобразовать значение типа «weatherJSON» в указанный тип «Массив», пусть JSON: Array = try JSONDecoder().decode(weatherJSON.self, from: data)   -  person Westopher    schedule 26.02.2019
comment
Вы не можете создать массив из одного объекта, аннотировав тип. Не зная содержания weatherJSON, ответить на вопрос практически невозможно.   -  person vadian    schedule 26.02.2019
comment
У меня есть файл модели со всеми выложенными и инициализированными структурами в другом файле того же проекта в Xcode.   -  person Westopher    schedule 26.02.2019
comment
Еще раз, не зная структур и того, что вы хотите отобразить, на вопрос нельзя ответить удовлетворительно.   -  person vadian    schedule 26.02.2019


Ответы (1)


Чтобы иметь лучший/более чистый код, возможно, вы захотите отделить вызов API в функции (может быть, func makeRequest() или что-то в этом роде), чтобы вызывать эту функцию только в вашем viewDidLoad.

У вас есть

var weatherList: [weatherJSON] = []

Это список с объектами WeatherJSON, которые вы хотите отобразить в таблице, но проблема заключается в вашем запросе, когда вы перезагружаете данные в таблицу, но не сохраняете свой ответ JSON в своем weatherList. Сначала вы должны сохранить ответ JSON в своей переменной weatherList или добавить результаты в этот массив. Таким образом, вы сможете заполнить свою таблицу, когда: cell.nameLabel?.text = weatherList[indexPath.row]

Кроме того, вам нужно добавить свойство объекта списка погоды, которое вы хотите показать. что-то вроде weatherList[indexPath.row].name или имени свойства, которым обладает объект.

Кроме того, я рекомендую использовать некоторые библиотеки для выполнения HTTP-запросов, такие как AlamoFire и SwiftyJson, чтобы сопоставить ваш ответ JSON с вашим объектом.

Используя упомянутые мной библиотеки, весь ваш вызов API и табличные функции могут быть такими: func getWeather(){

    let url: String = "http://example.com/api/weather/"

    AFWrapper.requestGETURL(url, success: {
        (JSONResponse) -> Void in

        for item in JSONResponse{
            let weatherList = [WeatherList(fromJson: item.1)]

            for weather in weatherList {
                self. weatherList.append(weather)
            }
        }

        self.tableView.reloadData()
    })
    {
        (error) -> Void in
        print("Error \(error)")
    }




}

И в вашей таблице func:

cell.nameLabel.text =  self.weatherList[indexPath.row].name

Этого можно достичь с помощью класса AlamoFireWrapper, чтобы сделать публикацию и получить запрос следующим образом: AlamoFireWrapper.swift

import UIKit
import Alamofire
import SwiftyJSON

class AFWrapper: NSObject {
    class func requestGETURL(_ strURL: String, success:@escaping (JSON) -> Void, failure:@escaping (Error) -> Void) {
        Alamofire.request(strURL).responseJSON { (responseObject) -> Void in



            if responseObject.result.isSuccess {
                let resJson = JSON(responseObject.result.value!)
                success(resJson)
            }
            if responseObject.result.isFailure {
                let error : Error = responseObject.result.error!
                failure(error)
            }
        }
    }

    class func requestPOSTURL(_ strURL : String, params : [String : AnyObject]?, headers : [String : String]?, success:@escaping (JSON) -> Void, failure:@escaping (Error) -> Void){

        Alamofire.request(strURL, method: .post, parameters: params, encoding: JSONEncoding.default, headers: headers).responseJSON { (responseObject) -> Void in



            if responseObject.result.isSuccess {
                let resJson = JSON(responseObject.result.value!)
                success(resJson)
            }
            if responseObject.result.isFailure {
                let error : Error = responseObject.result.error!
                failure(error)
            }
        }
    }
}
person Gabo Ruiz    schedule 25.02.2019
comment
Габо, спасибо, что показал мне это. Я не знаю, зачем использовать Alamofire сейчас, когда вы можете использовать декодируемый? В декодируемом гораздо меньше кода, и он не является внешним, поэтому он гораздо более стабилен с течением времени, да? Я не хочу противоречить, и я ценю ваш ответ, однако я искренне озадачен тем, в чем преимущество использования Alamofire, если вы можете получить JSON без его использования? - person Westopher; 26.02.2019
comment
Кроме того, я только учусь, поэтому я буквально просто пытаюсь заставить свой JSON заполнить табличное представление. Это все, что я хочу сделать; первые детские шаги... - person Westopher; 26.02.2019
comment
Вы не должны рекомендовать библиотеки, которые легко заменить библиотеками Apple, если они не предлагают положительных преимуществ по сравнению с эквивалентом Apple. Alamofire очень избыточен с URLSession, а SwiftyJSON становится избыточным с помощью Codable. - person Sean Lintern; 26.02.2019
comment
Спасибо @SeanLintern88; Я относительно новичок в кодировании, но я думаю то же самое. Можете ли вы взглянуть на проблему выше и помочь мне с этим решением? Я действительно хочу успешно победить этого плохого парня, используя только URLSession и Codable. Спасибо! - person Westopher; 26.02.2019