Проблемы с переключением с UIKit на SwiftUI и передачей данных API в представлениеIOS

Программируем под IOS
Ответить
Anonymous
 Проблемы с переключением с UIKit на SwiftUI и передачей данных API в представление

Сообщение Anonymous »

Я только что преобразовал свое приложение в платформу SwiftUI. Интерфейс работает отлично, но у меня возникла огромная проблема: я не могу понять, как получить данные из пользовательской записи UITextField и обновить свое представление. В этом проекте много кода, но я сжал его в несколько файлов и поделюсь только частью, поскольку остальные части приложения структурированы аналогичным образом. Я был бы очень признателен за помощь, которую может предложить каждый. Я намерен заменить многие строки в текстовых метках METARView переменными, основанными на декодированных данных вызова API.
Внешний интерфейс: ContentView()
//
// ContentView.swift
// Aviate
//
// Created by Grayson Bertaina on 9/27/20.
//
import Combine
import SwiftUI
import Foundation

class Query: ObservableObject {
var didChange = PassthroughSubject()
}

struct ContentView: View {

init() {
UITableView.appearance().backgroundColor = .clear
}

@State var stationQuery: String = ""

var body: some View {

NavigationView{

VStack {
Text("The App for GA Pilots")
Spacer()

VStack(alignment: .leading){
Text("News")
.background(Color.blue)
.font(.title)
.padding()

Text("Aviate now supports chart lookup functionality!")
.padding()

}
.background(Color.blue)
.foregroundColor(.white)
.padding()

VStack(alignment: .leading) {

Text("Favorite Airports")
.font(.title)
.padding()

List {

Section(header: Text("Favorite Airports")) {
NavigationLink(destination: METARView(search: stationQuery)) {
Text("Airport 1")
}
}

Section(header: Text("Nearby Stations")) {
NavigationLink(destination: METARView(search: stationQuery)) {
Text("Airport 1")
}
}
}

}

Spacer()

HStack{
TextField("Enter ICAO", text: $stationQuery)
.padding()
.border(Color.black)

NavigationLink(destination: METARView(search: stationQuery)) {
Text("Search")

}
.padding()
.background(Color.blue)
.foregroundColor(.white)
}
.padding()

}
.navigationBarTitle("Aviate Home")

}

}

}

struct METARView: View {

@State var weatherManager = WeatherManager()

init(search: String) {
self.weatherManager.fetchWeather(stationICAO: search)
}

var body: some View {

ScrollView{

METARReport(model: weatherManager.weather)
MapView()
.frame(height: 200)
.edgesIgnoringSafeArea(/*@START_MENU_TOKEN@*/.all/*@END_MENU_TOKEN@*/)

METARTitleView()
.frame(height: 250)

METARReport()

Spacer()
}
.edgesIgnoringSafeArea(/*@START_MENU_TOKEN@*/.all/*@END_MENU_TOKEN@*/)
}

}

struct TAFView: View {

var search: String

var body: some View {

ScrollView{
MapView()
.frame(height: 200)
.edgesIgnoringSafeArea(/*@START_MENU_TOKEN@*/.all/*@END_MENU_TOKEN@*/)
METARTitleView()
.frame(height: 250)

TAFReport()

}
.edgesIgnoringSafeArea(/*@START_MENU_TOKEN@*/.all/*@END_MENU_TOKEN@*/)
}
}

struct AirportView: View {

var search: String

var body: some View {

ScrollView{
MapView()
.frame(height: 200)
.edgesIgnoringSafeArea(/*@START_MENU_TOKEN@*/.all/*@END_MENU_TOKEN@*/)

AirportReport()

}
.edgesIgnoringSafeArea(/*@START_MENU_TOKEN@*/.all/*@END_MENU_TOKEN@*/)
}
}

struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.previewDevice("iPhone 11")

}
}

final class DataModel: ObservableObject {
static let shared = DataModel()
@Published var observedString = "" {
didSet {
//RUNS SUCCESSFULLY
print("Observed string changed to \(observedString)")
}
}
}


Вот часть METARView(), которая необходима для понимания того, куда передаются данные — она представит извлеченные данные.
METARReport( )
//
// METARReport.swift
// Aviate
//
// Created by Grayson Bertaina on 9/29/20.
//

import SwiftUI
import Foundation

var weatherManager = WeatherManager()

struct METARReport: View {

var body: some View {
ScrollView {
VStack{
HStack{
Text("METAR Report")
.font(.title)

Spacer()
Text("Time: " + "")
.font(.headline)
}

.padding()

HStack{
Text("Flight Rules")

Spacer()
Text("VFR")
.padding()
.background(Color.green)

}
.padding()
.font(.headline)

HStack(spacing: 20){
VStack(alignment: .leading){
Text("Visibility")

Spacer()
Text("10" + " SM")

}

VStack(alignment: .leading){
Text("Temperature")

Spacer()
Text("25" + " °C")

}

VStack(alignment: .leading){
Text("Dew Point")

Spacer()
Text("25" + " °C")

}

}
.padding()
.font(.headline)

VStack(alignment: .center){
Text("Clouds")
.font(.headline)
.padding()

HStack() {
Text("Few")
Spacer()

Text("1200")
}
.padding()
HStack() {
Text("Few")
Spacer()

Text("1200")
}
.padding()
HStack() {
Text("Few")
Spacer()

Text("1200")
}
.padding()
}
.font(.headline)

HStack{
Text("Altimeter")

Spacer()
Text("29.92")

}
.font(.headline)
.padding()

VStack{
Text("Wind")
HStack{
Text("5" + "kt")
Text("G")
Text("12" + "kt")
Text("From")
Text("310" + "°")

}
.padding()

}
.font(.headline)

HStack {
Text("Special Wx")
Spacer()
Text("+RA")
}
.padding()
.font(.headline)

VStack {
Text("Remarks")
Spacer()
Text("No Remarks")
}
.padding()
.font(.headline)
}
}
}
}

struct METARReport_Previews: PreviewProvider {
static var previews: some View {
METARReport()
}
}

Внутренняя часть: WeatherStorage (содержит WeatherData, WeatherModel и WeatherManager с вызовом API)
struct WeatherData: Codable {

let flight_rules: String?
let remarks: String?
let wind_speed: WindSpeed?
let wind_gust: WindGust?
let wind_direction: WindDirection?
let visibility: Visibility?
let time: Time?
let station: String?
let temperature: Temperature?
let raw: String?
let clouds: [Clouds?]
let wx_codes: [Wxcodes?]
}

struct Clouds: Codable {
let type: String
let altitude: Int
}

struct Time: Codable {
let repr: String
}

struct WindSpeed: Codable {
let value: Int
}

struct WindGust: Codable {
let value: Int
}

struct WindDirection: Codable {
let repr: String
}

struct Visibility: Codable {
let repr: String
}

struct Remarks: Codable {
let remarks: String
}

struct Altimeter: Codable {
let repr: String?
let spoken: String?
}

struct Temperature: Codable {
let repr: String
}

struct Dewpoint: Codable {
let repr: String
}

struct Wxcodes: Codable {
let value: String
}

// WeatherModel

//
// WeatherModel.swift
// AvWx Pro
//
// Created by Grayson Bertaina on 9/22/20.
//

import Foundation

struct WeatherModel {
let reportingStation: String
let windGust: Int
let windSpeed: Int
let windDirection: String
let visibility: String
let flightRules: String
let time: String
let remarks: String
let temperature: String
let dewpoint: String
let rawMETAR: String
let lowestCloudsType: String
let lowestCloudsAlt: Int
let middleCloudsType: String
let middleCloudsAlt: Int
let highestCloudsType: String
let highestCloudsAlt: Int
let firstWxCode: String

var windGustString: String {
return String(format: "%u" + "kt", windGust)
}

var windSpeedString: String {
return String(format: "%u" + "kt", windSpeed)
}

var visUnits: String {
return visibility + " SM"
}

var degUnits: String {
return windDirection + "°"
}

var tempUnits: String {
return temperature + "°C"
}

var dewUnits: String {
return dewpoint + "°C"
}

var altToString1: String {
return String(format: "%u" + "00 ft", lowestCloudsAlt)
}

var altToString2: String {
return String(format: "%u" + "00 ft", middleCloudsAlt)
}

var altToString3: String {
return String(format: "%u" + "00 ft", highestCloudsAlt)
}

var flightConditions: String {
switch flightRules {
case "VFR":
return "green"
case "MVFR":
return "blue"
case "IFR":
return "red"
case "LIFR":
return "purple"
default:
return "gray"

}
}
}

private func parseJSON(_ weatherData: Data) -> WeatherModel? {
do {
let decoder = JSONDecoder()
let decodedData = try decoder.decode(WeatherData.self, from: weatherData)

let clouds = decodedData.clouds
let wxcodes = decodedData.wx_codes
let reportingStationVar = decodedData.station ?? "N/A"
let windGustValue = decodedData.wind_gust?.value ?? 0
let windSpeedValue = decodedData.wind_speed?.value ?? 0
let windDirectionValue = decodedData.wind_direction?.repr ?? "N/A"
let visibilityValue = decodedData.visibility?.repr ?? "N/A"
let flightRulesValue = decodedData.flight_rules ?? "N/A"
let timeReportedMETAR = decodedData.time?.repr ?? "N/A"
let remarksReportedMETAR = decodedData.remarks ?? "N/A"
let tempMETAR = decodedData.temperature?.repr ?? "No Data"
let rawMETARData = decodedData.raw ?? "N/A"
let lowCloudsType = (clouds.count > 0 ? clouds[0]?.type : nil) ?? "N/A"
let midCloudsType = (clouds.count > 1 ? clouds[1]?.type : nil) ?? "N/A"
let highCloudsType = (clouds.count > 2 ? clouds[2]?.type : nil) ?? "N/A"
let lowCloudsAlt = (clouds.count > 0 ? clouds[0]?.altitude : nil) ?? 0
let midCloudsAlt = (clouds.count > 1 ? clouds[1]?.altitude : nil) ?? 0
let highCloudsAlt = (clouds.count > 2 ? clouds[2]?.altitude : nil) ?? 0
let firstWxCode1 = (wxcodes.count > 0 ? wxcodes[0]?.value : "N/A") ?? "N/A"

let weather = WeatherModel(reportingStation: reportingStationVar, windGust: windGustValue, windSpeed: windSpeedValue, windDirection: windDirectionValue, visibility: visibilityValue, flightRules: flightRulesValue, time: timeReportedMETAR, remarks: remarksReportedMETAR, temperature: tempMETAR, dewpoint: rawMETARData, rawMETAR: rawMETARData, lowestCloudsType: lowCloudsType, lowestCloudsAlt: lowCloudsAlt, middleCloudsType: midCloudsType, middleCloudsAlt: midCloudsAlt, highestCloudsType: highCloudsType, highestCloudsAlt: highCloudsAlt, firstWxCode: firstWxCode1)

return weather

} catch {
print(error)
return nil
}
}


Вы заметите, что есть несколько бесполезных функций, например попытка fetchWeather в верхней части моего ContentView. Я пытаюсь разными способами получить данные, но не знаю, куда поместить необходимое:
  • функцию fetchWeather и что инициализировать

    функцию fetchWeather и что инициализировать

    функцию fetchWeather li>
    Как обновить представления и инициализировать WeatherModel или WeatherManager для получения этих данных.
Я новичок в Swift, поэтому Прошу прощения, если какая-то часть моего вопроса неясна. Я определенно немного не в себе! Спасибо за помощь и хорошего дня.
Добавить:
//
// WeatherData.swift
// SwitUIAppExample
//
// Created by mac on 30/09/2020.
// Copyright © 2020 Kamran. All rights reserved.
//

//
// WeatherData.swift
// AvWx Pro
//
// Created by Grayson Bertaina on 9/21/20.
//

import Foundation

struct WeatherData: Codable {

let clouds: [Clouds?]
let flight_rules: String?
let remarks: String?
let wind_speed: WindSpeed?
let wind_gust: WindGust?
let wind_direction: WindDirection?
let visibility: Visibility?
let time: Time?
let station: String?
let altimeter: Altimeter?
let temperature: Temperature?
let dewpoint: Dewpoint?
let wx_codes: [Wxcodes?]
let raw: String?
}

struct Clouds: Codable {
let type: String
let altitude: Int
}

struct Time: Codable {
let repr: String
}

struct WindSpeed: Codable {
let value: Int
}

struct WindGust: Codable {
let value: Int
}

struct WindDirection: Codable {
let repr: String
}

struct Visibility: Codable {
let repr: String
}

struct Remarks: Codable {
let remarks: String
}

struct Altimeter: Codable {
let value: Double
}

struct Temperature: Codable {
let repr: String
}

struct Dewpoint: Codable {
let repr: String
}

struct Wxcodes: Codable {
let value: String
}

// WeatherModel

//
// WeatherModel.swift
// AvWx Pro
//
// Created by Grayson Bertaina on 9/22/20.
//

import Foundation

struct WeatherModel {

let lowestCloudsType: String
let lowestCloudsAlt: Int
let middleCloudsType: String
let middleCloudsAlt: Int
let highestCloudsType: String
let highestCloudsAlt: Int
let reportingStation: String
let windGust: Int
let windSpeed: Int
let windDirection: String
let visibility: String
let flightRules: String
let time: String
let remarks: String
let altimeter: Double
let temperature: String
let dewpoint: String
let firstWxCode: String
let rawMETAR: String

var altToString1: String {
return String(format: "%u" + "00 ft", lowestCloudsAlt)
}

var altToString2: String {
return String(format: "%u" + "00 ft", middleCloudsAlt)
}

var altToString3: String {
return String(format: "%u" + "00 ft", highestCloudsAlt)
}

var windGustString: String {
return String(format: "%u" + "kt", windGust)
}

var windSpeedString: String {
return String(format: "%u" + "kt", windSpeed)
}

var altimeterString: String {
return String(format: "%.2f" + " inHg", altimeter as CVarArg)
}

var visUnits: String {
return visibility + " SM"
}

var degUnits: String {
return windDirection + "°"
}

var tempUnits: String {
return temperature + "°C"
}

var dewUnits: String {
return dewpoint + "°C"
}

var flightConditions: String {
switch flightRules {
case "VFR":
return "green"
case "MVFR":
return "blue"
case "IFR":
return "red"
case "LIFR":
return "purple"
default:
return "gray"

}
}
}

// WeatherManager

//
// WeatherManager.swift
// AvWx Pro
//
// Created by Grayson Bertaina on 9/21/20.
//

import Foundation

class WeatherManager: ObservableObject {

@Published var weater: WeatherModel?

let weatherURL = "https://avwx.rest/api/metar/"

func fetchWeather (stationICAO: String) {
let urlString = "\(weatherURL)\(stationICAO)?token=OVi45FiTDo1LmyodShfOfoizNe5m9wyuO6Mkc95AN-c"
performRequest(with: urlString)
}

func performRequest (with urlString: String) {
if let url = URL(string: urlString) {
let session = URLSession(configuration: .default)

let task = session.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error)
return
}

if let safeData = data {
self.weater = self.parseJSON(safeData)
}
}

task.resume()
print(urlString)

}
}

private func parseJSON(_ weatherData: Data) -> WeatherModel? {
do {
let decoder = JSONDecoder()
let decodedData = try decoder.decode(WeatherData.self, from: weatherData)

let clouds = decodedData.clouds
let wxcodes = decodedData.wx_codes
let lowCloudsType = (clouds.count > 0 ? clouds[0]?.type : nil) ?? "N/A"
let midCloudsType = (clouds.count > 1 ? clouds[1]?.type : nil) ?? "N/A"
let highCloudsType = (clouds.count > 2 ? clouds[2]?.type : nil) ?? "N/A"
let lowCloudsAlt = (clouds.count > 0 ? clouds[0]?.altitude : nil) ?? 0
let midCloudsAlt = (clouds.count > 1 ? clouds[1]?.altitude : nil) ?? 0
let highCloudsAlt = (clouds.count > 2 ? clouds[2]?.altitude : nil) ?? 0
let reportingStationVar = decodedData.station ?? "N/A"
let windGustValue = decodedData.wind_gust?.value ?? 0
let windSpeedValue = decodedData.wind_speed?.value ?? 0
let windDirectionValue = decodedData.wind_direction?.repr ?? "N/A"
let visibilityValue = decodedData.visibility?.repr ?? "N/A"
let flightRulesValue = decodedData.flight_rules ?? "N/A"
let timeReportedMETAR = decodedData.time?.repr ?? "N/A"
let remarksReportedMETAR = decodedData.remarks ?? "N/A"
let altimeterMETAR = decodedData.altimeter?.value ?? 0
let tempMETAR = decodedData.temperature?.repr ?? "No Data"
let dewMETAR = decodedData.dewpoint?.repr ?? "No Data"
let firstWxCode1 = (wxcodes.count > 0 ? wxcodes[0]?.value : "N/A") ?? "N/A"
let rawMETARData = decodedData.raw ?? "N/A"

let weather = WeatherModel(lowestCloudsType: lowCloudsType , lowestCloudsAlt: lowCloudsAlt, middleCloudsType: midCloudsType , middleCloudsAlt: midCloudsAlt, highestCloudsType: highCloudsType , highestCloudsAlt: highCloudsAlt, reportingStation: reportingStationVar, windGust: windGustValue, windSpeed: windSpeedValue, windDirection: windDirectionValue, visibility: visibilityValue, flightRules: flightRulesValue, time: timeReportedMETAR, remarks: remarksReportedMETAR, altimeter: altimeterMETAR, temperature: tempMETAR, dewpoint: dewMETAR, firstWxCode: firstWxCode1, rawMETAR: rawMETARData)
return weather

} catch {
print(error)
return nil
}
}

}


Подробнее здесь: https://stackoverflow.com/questions/641 ... o-the-view
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «IOS»