Невозможно извлечь данные из наблюдаемого объекта - PullRequest
0 голосов
/ 17 января 2020

Я пытаюсь отобразить данные от наблюдаемого объекта.

Первоначально я пытался сделать это простым, чтобы просто отобразить один элемент структуры: 'base' (значение: "станции").

struct Sample: Codable {
    let coord: Coord
    let weather: [Weather]
    let base: String
    let main: Main
    let visibility: Int
    let wind: Wind
    let clouds: Clouds
    let dt: Double
//    let sys: Sys
    let id: Int
    let name: String
//    let cod: Int
}

Я сделал защитное кодирование с помощью '?' но я получил следующую ошибку компилятора:

enter image description here

Итак, я заменил '?' с '!', зная, что у меня должны быть какие-то данные.

enter image description here

Я нахожу это разочаровывающим, исходя из императивно-парадигмального фона. Что я делаю не так?

Вот дамп данных:

Пример (координаты: DataTaskPubTab.Coord (lon: -0.13, широта: 51.51), погода: [DataTaskPubTab.Weather (id: 300, основной: «Морось», описание: «моросящий свет»)], база: «станции», главный: DataTaskPubTab.Main (температура: 280,32, давление: 1012, влажность: 81, температура: 279,15, температура: Макс. : 281.15), видимость: 10000, ветер: DataTaskPubTab.Wind (скорость: 4.1, град: 80), облака: DataTaskPubTab.Clouds (все: 90), dt: 1485789600.0, id: 2643743, имя: «Лондон»)

Вот наблюдаемый объект:

class StandardWeatherReportLoader: ObservableObject {
    @Published var networkMessage: String?
    @Published var hasAlert = false
    @Published var weatherReport: Sample?
    @Published var hasReport = false

    func doStandard() {
        let url = EndPoint.weather.path()
        var request = URLRequest(url: EndPoint.weather.path()!)
        request.httpMethod = "GET"
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")

        let task = URLSession.shared.dataTask(with: url!) { (data: Data?, _: URLResponse?, error: Error?) -> Void in
            DispatchQueue.main.async {
                guard error == nil else {
                    self.networkMessage = error?.localizedDescription
                    self.hasAlert = true
                    return
                }

                do {
                    let decoder = JSONDecoder()
                    decoder.keyDecodingStrategy = .convertFromSnakeCase
                    let result = try decoder.decode(Sample.self, from: data!)
                    self.weatherReport = result
                    self.hasReport = true
                    print(result)
                } catch let error as NSError {
                    print(error)
                }
            }
        }
        task.resume()
    }
}

Ответы [ 2 ]

0 голосов
/ 24 января 2020

Очень вероятно, что данные веб-сервисов пока недоступны при первом отображении представления. Поэтому не следует принудительно развертывать значение с помощью !. Если вы хотите создать элемент Text() в обоих случаях, вы можете просто использовать операцию ?? (см. Оператор Nil-Coalescing в документации по языку Swift):

Text(standardWeatherReportLoader.weatherReport?.base ?? "Sorry, NO data.")
0 голосов
/ 17 января 2020

Видимо, это работает:

struct StandardWeatherView: View {
    @EnvironmentObject var settings: Settings
    @ObservedObject var standardWeatherReportLoader = StandardWeatherReportLoader()

    init() {
        self.standardWeatherReportLoader.doStandard()
    }

    var body: some View {
        NavigationView {
            ZStack {
                Color("FernGreen").edgesIgnoringSafeArea(.all)
                VStack {
                    if standardWeatherReportLoader.weatherReport?.base == nil {
                        Text("Sorry, NO data.")
                    } else {
                        Text(standardWeatherReportLoader.weatherReport!.base)
                    }

                    Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
                }
                .navigationBarTitle(Text("Weather Report"), displayMode: .inline)
            }.alert(isPresented: $standardWeatherReportLoader.hasAlert, content: { () -> Alert in
                Alert(title: Text(verbatim: standardWeatherReportLoader.networkMessage!))
            })
        }
    }
}

enter image description here

...