API Call Data Issues with Passing to New View Controller - Swift - ios

I am building a swift app and hit an issue where the data I get back from an API call is not being passed to the view controller. I have uilabels all over the page and they do not update after the query is made like I intended. I am trying to present the aviation weather data from the user on the view controller ReportViewController.
I can get the data to fill labels on the WxViewController, but don't understand why I can't mirror the same code to have it display on the ReportViewController instead. I have tried copy/paste and removing the same code from the WxViewController as well as having it in both places, but the only place that updates the label is WxViewController (testTextLabel). Any help getting out of this endless cycle would be appreciated!
WxViewController
//
// WxViewController.swift
// AvWx Pro
//
// Created by Grayson Bertaina on 9/21/20.
//
import UIKit
class WxViewController: UIViewController, UITextFieldDelegate, WeatherManagerDelegate {
var weatherManager = WeatherManager()
#IBOutlet weak var testTextField: UILabel!
#IBOutlet weak var stationSearch: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
weatherManager.delegate = self
stationSearch.delegate = self
}
#IBAction func searchPressed(_ sender: Any) {
print(stationSearch.text!)
stationSearch.endEditing(true)
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
print(stationSearch.text!)
stationSearch.endEditing(true)
return true
}
func textFieldDidEndEditing(_ textField: UITextField) {
if let station = stationSearch.text {
weatherManager.fetchWeather(stationICAO: station)
}
stationSearch.text = ""
}
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
if stationSearch.text != "" {
return true
} else {
stationSearch.placeholder = "Type an ICAO"
return false
}
}
func didUpdateWeather(_ weatherManager: WeatherManager, weather: WeatherModel) {
DispatchQueue.main.async {
self.testTextField.text = weather.flightConditions
}
print(weather.flightConditions)
}
func didFailWithError(error: Error) {
print(error)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
}
ReportViewController
//
// ReportViewController.swift
// AvWx Pro
//
// Created by Grayson Bertaina on 9/22/20.
//
import UIKit
class ReportViewController: UIViewController, WeatherManagerDelegate {
var weatherManager = WeatherManager()
#IBOutlet weak var flightRulesTitleLabel: UILabel!
#IBOutlet weak var flightRulesValueLabel: UILabel!
#IBOutlet weak var visibilityValueLabel: UILabel!
#IBOutlet weak var altimeterValueLabel: UILabel!
#IBOutlet weak var cloudsTitleLabel: UILabel!
#IBOutlet weak var cloudsType1Label: UILabel!
#IBOutlet weak var cloudsAltitude1Label: UILabel!
#IBOutlet weak var cloudsType2Label: UILabel!
#IBOutlet weak var cloudsAltitude2Label: UILabel!
#IBOutlet weak var cloudsType3Label: UILabel!
#IBOutlet weak var cloudsAltitude3Label: UILabel!
#IBOutlet weak var windGTextLabel: UILabel!
#IBOutlet weak var windSpeedValueLabel: UILabel!
#IBOutlet weak var windGustValueLabel: UILabel!
#IBOutlet weak var windFromTextLabel: UILabel!
#IBOutlet weak var windDirectionValueLabel: UILabel!
#IBOutlet weak var remarksValueLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
weatherManager.delegate = self
}
func didUpdateWeather(_ weatherManager: WeatherManager, weather: WeatherModel) {
DispatchQueue.main.async {
self.flightRulesValueLabel.text = weather.flightConditions
print(weather.flightConditions)
}
}
func didFailWithError(error: Error) {
print(error)
}
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
}
WeatherManager
//
// WeatherManager.swift
// AvWx Pro
//
// Created by Grayson Bertaina on 9/21/20.
//
import Foundation
protocol WeatherManagerDelegate : class {
func didUpdateWeather(_ weatherManager: WeatherManager, weather: WeatherModel)
func didFailWithError(error: Error)
}
struct WeatherManager {
let weatherURL = "https://avwx.rest/api/metar/"
weak var delegate : WeatherManagerDelegate?
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 {
self.delegate?.didFailWithError(error: error!)
return
}
if let safeData = data {
if let weather = self.parseJSON(safeData) {
self.delegate?.didUpdateWeather(self, weather: weather)
}
}
}
task.resume()
print(urlString)
}
}
func parseJSON(_ weatherData: Data) -> WeatherModel? {
do {
let decoder = JSONDecoder()
let decodedData = try decoder.decode(WeatherData.self, from: weatherData)
let clouds = decodedData.clouds
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?.value ?? 999
let visibilityValue = decodedData.visibility?.value ?? 0
let flightRulesValue = decodedData.flight_rules ?? "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)
delegate?.didUpdateWeather(self, weather: weather)
return weather
} catch {
delegate?.didFailWithError(error: error)
return nil
}
}
}
WeatherData
//
// 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 station: String?
}
struct Clouds: Codable {
let type: String
let altitude: Int
}
struct WindSpeed: Codable {
let value: Int
}
struct WindGust: Codable {
let value: Int
}
struct WindDirection: Codable {
let value: Int
}
struct Visibility: Codable {
let value: Int
}
Again, I really appreciate the help! There are no errors when I run my code.

Related

Swift I can't move data with delegate

I'm trying to make a quiz application using the API, I can import the
data into the quizManager file, but I can't transfer the data to the
viewController, When I try to print in quizManger, I can print, but in viewController does not.
how do I move data to viewController?
QuizManager
import Foundation
protocol quizManagerDelegate {
func didUpdateQuiz(_ Quizmanager: QuizManager ,quiz: QuizModel)
}
struct QuizManager {
var delegate: quizManagerDelegate?
func performRequest(){
let urlString = "https://opentdb.com/api.php?amount=1&type=multiple"
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{
if let quiz = self.parseJSON(quizdata: safeData){
delegate?.didUpdateQuiz(self, quiz: quiz)
}
}
}
task.resume()
}
}
func handle(data: Data?, response: URLResponse?, error: Error?) -> Void {
}
func parseJSON(quizdata: Data) -> QuizModel? {
let decoder = JSONDecoder()
do{
let decodedData = try decoder.decode(Welcome.self, from: quizdata)
let correct = decodedData.results?[0].correct_answer ?? "error"
let quest = decodedData.results?[0].question ?? "error"
let incorrect = decodedData.results?[0].incorrect_answers ?? ["error"]
let question = QuizModel(correctAnswer: correct, question: quest, falseAnswer: incorrect)
// print(question.correctAnswer)
// print(question.question)
// print(question.falseAnswer)
return question
} catch {
print(error)
return nil
}
}
}
QuizData
import Foundation
// MARK: - Welcome
struct Welcome: Codable {
let results: [Result]?
}
// MARK: - Result
struct Result: Codable {
let category: String?
let question, correct_answer: String?
let incorrect_answers: [String]?
}
QuizModel
import Foundation
struct QuizModel {
let correctAnswer : String
let question : String
let falseAnswer : [String]
}
ViewController
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var ChoiceButton4: UIButton!
#IBOutlet weak var ChoiceButton3: UIButton!
#IBOutlet weak var ChoiceButton2: UIButton!
#IBOutlet weak var ChoiceButton1: UIButton!
#IBOutlet weak var QuestionTextView: UITextView!
var quizMangager = QuizManager()
override func viewDidLoad() {
super.viewDidLoad()
QuestionTextView.layer.cornerRadius = 15
quizMangager.performRequest()
self.quizMangager.delegate = self
}
}
extension ViewController : quizManagerDelegate{
func didUpdateQuiz(_ Quizmanager: QuizManager, quiz: QuizModel) {
DispatchQueue.main.async {
print("***")
print(quiz.correctAnswer)
}
}
}
The problem is in viewDidLoad that lines
quizMangager.performRequest()
self.quizMangager.delegate = self
You call performRequest before to delegate it so when performRequest is called var delegate: quizManagerDelegate? is nil . Just call delegate before call function
override func viewDidLoad() {
super.viewDidLoad()
...
quizMangager.delegate = self
quizMangager.performRequest()
...
}
You have a slight mistake in your code. You just need to confirm the delegate first and then call its function .

How to send data in extension to Button function

I'm trying to make a quiz application using the API, I can take api data and show on app but I cannot transfer data from extension in viewController to button pressed.right now, when click the button, I want the clicked option to be green or red, how can I do it?
QuizManager
import Foundation
protocol quizManagerDelegate {
func didUpdateQuiz(_ Quizmanager: QuizManager ,quiz: QuizModel)
}
struct QuizManager {
var delegate: quizManagerDelegate?
func performRequest(){
let urlString = "https://opentdb.com/api.php?amount=1&type=multiple"
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{
if let quiz = self.parseJSON(quizdata: safeData){
delegate?.didUpdateQuiz(self, quiz: quiz)
}
}
}
task.resume()
}
}
func handle(data: Data?, response: URLResponse?, error: Error?) -> Void {
}
func parseJSON(quizdata: Data) -> QuizModel? {
let decoder = JSONDecoder()
do{
let decodedData = try decoder.decode(Welcome.self, from: quizdata)
let correct = decodedData.results?[0].correct_answer ?? "error"
let quest = decodedData.results?[0].question ?? "error"
let incorrect = decodedData.results?[0].incorrect_answers ?? ["error"]
let question = QuizModel(correctAnswer: correct, question: quest, falseAnswer: incorrect)
return question
} catch {
print(error)
return nil
}
}
}
QuizData
import Foundation
// MARK: - Welcome
struct Welcome: Codable {
let results: [Result]?
}
// MARK: - Result
struct Result: Codable {
let category: String?
let question, correct_answer: String?
let incorrect_answers: [String]?
}
QuizModel
import Foundation
struct QuizModel {
let correctAnswer : String
let question : String
let falseAnswer : [String]
}
ViewController
import UIKit
import GameKit
class ViewController: UIViewController {
#IBOutlet weak var ChoiceButton4: UIButton!
#IBOutlet weak var ChoiceButton3: UIButton!
#IBOutlet weak var ChoiceButton2: UIButton!
#IBOutlet weak var ChoiceButton1: UIButton!
#IBOutlet weak var QuestionTextView: UITextView!
var quizMangager = QuizManager()
#IBAction func OptionsButtonPressed(_ sender: UIButton) {
}
override func viewDidLoad() {
super.viewDidLoad()
QuestionTextView.layer.cornerRadius = 15
quizMangager.delegate = self
quizMangager.performRequest()
}
}
extension ViewController : quizManagerDelegate{
func didUpdateQuiz(_ Quizmanager: QuizManager, quiz: QuizModel) {
DispatchQueue.main.async { [self] in
self.QuestionTextView.text = quiz.question
var allOptions = []
allOptions.append(quiz.falseAnswer[0])
allOptions.append(quiz.falseAnswer[1])
allOptions.append(quiz.falseAnswer[2])
allOptions.append(quiz.correctAnswer)
let generatedValue = Array(allOptions.shuffled().prefix(4))
print(generatedValue)
print(quiz.correctAnswer)
ChoiceButton1.setTitle(generatedValue[0] as? String, for: .normal)
ChoiceButton2.setTitle(generatedValue[1] as? String, for: .normal)
ChoiceButton3.setTitle(generatedValue[2] as? String, for: .normal)
ChoiceButton4.setTitle(generatedValue[3] as? String, for: .normal)
}
}
}
ViewController
import UIKit
import GameKit
class ViewController: UIViewController {
#IBOutlet weak var ChoiceButton4: UIButton!
#IBOutlet weak var ChoiceButton3: UIButton!
#IBOutlet weak var ChoiceButton2: UIButton!
#IBOutlet weak var ChoiceButton1: UIButton!
#IBOutlet weak var QuestionTextView: UITextView!
var quizMangager = QuizManager()
#IBAction func OptionsButtonPressed(_ sender: UIButton) {
}
override func viewDidLoad() {
super.viewDidLoad()
QuestionTextView.layer.cornerRadius = 15
quizMangager.delegate = self
quizMangager.performRequest()
}
}
extension ViewController : quizManagerDelegate{
func didUpdateQuiz(_ Quizmanager: QuizManager, quiz: QuizModel) {
DispatchQueue.main.async { [self] in
self.QuestionTextView.text = quiz.question
var allOptions = []
allOptions.append(quiz.falseAnswer[0])
allOptions.append(quiz.falseAnswer[1])
allOptions.append(quiz.falseAnswer[2])
allOptions.append(quiz.correctAnswer)
let generatedValue = Array(allOptions.shuffled().prefix(4))
print(generatedValue)
print(quiz.correctAnswer)
ChoiceButton1.setTitle(generatedValue[0] as? String, for: .normal)
ChoiceButton2.setTitle(generatedValue[1] as? String, for: .normal)
ChoiceButton3.setTitle(generatedValue[2] as? String, for: .normal)
ChoiceButton4.setTitle(generatedValue[3] as? String, for: .normal)
}
}
}
You need to "hold onto the quiz data."
So, add a var property to your view controller:
var quizMangager = QuizManager()
// add this
var theQuiz: QuizModel?
then, in your didUpdateQuiz func, set that property:
func didUpdateQuiz(_ Quizmanager: QuizManager, quiz: QuizModel) {
DispatchQueue.main.async { [self] in
// add this
self.theQuiz = quiz
self.QuestionTextView.text = quiz.question
// ... no other changes
Now, connect all your buttons to #IBAction func OptionsButtonPressed and try this:
#IBAction func OptionsButtonPressed(_ sender: UIButton) {
guard let thisQuiz = theQuiz,
let btnTitle = sender.currentTitle
else { return }
if btnTitle == thisQuiz.correctAnswer {
sender.setTitleColor(.systemGreen, for: [])
} else {
sender.setTitleColor(.systemRed, for: [])
}
}

Question about passing data from an API into a view controller after user query - Swift

I am working tirelessly on an app and I'm pretty new to Swift. I am trying to take data from an API call after user entry on the landing screen and then present the results of the API call on the modal popover that comes up to display the data that the user wanted. This is an aviation weather app; The user enters something like "KDAB" and the API returns the current aviation weather at that airport. I have a bunch of labels set up for different values and can print them to console after a search but can't seem to get them printed in the VC. I have tried some destination.segue fixes but don't see why I would use them - the data is coming directly from the decoded JSON. Help would be appreciated!
I am trying to display on the ReportViewController in each of the value labels. I.E. Wind speed in the windSpeedValueLabel by utilizing the .text property.
Right now, nothing changes from the default labels on the actual ReportViewController.
Thanks again.
My code:
//
// ReportViewController.swift
// AvWx Pro
//
// Created by Grayson Bertaina on 9/22/20.
//
import UIKit
class ReportViewController: UIViewController, WeatherManagerDelegate {
var weatherManager = WeatherManager()
#IBOutlet weak var flightRulesTitleLabel: UILabel!
#IBOutlet weak var flightRulesValueLabel: UILabel!
#IBOutlet weak var visibilityValueLabel: UILabel!
#IBOutlet weak var altimeterValueLabel: UILabel!
#IBOutlet weak var cloudsTitleLabel: UILabel!
#IBOutlet weak var cloudsType1Label: UILabel!
#IBOutlet weak var cloudsAltitude1Label: UILabel!
#IBOutlet weak var cloudsType2Label: UILabel!
#IBOutlet weak var cloudsAltitude2Label: UILabel!
#IBOutlet weak var cloudsType3Label: UILabel!
#IBOutlet weak var cloudsAltitude3Label: UILabel!
#IBOutlet weak var windGTextLabel: UILabel!
#IBOutlet weak var windSpeedValueLabel: UILabel!
#IBOutlet weak var windGustValueLabel: UILabel!
#IBOutlet weak var windFromTextLabel: UILabel!
#IBOutlet weak var windDirectionValueLabel: UILabel!
#IBOutlet weak var remarksValueLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
func didUpdateWeather(_ weatherManager: WeatherManager, weather: WeatherModel) {
DispatchQueue.main.async {
self.flightRulesValueLabel.text = weather.flightRules
self.cloudsType1Label.text = weather.lowestCloudsType
}
}
func didFailWithError(error: Error) {
print(error)
}
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
}
//
// ViewController.swift
// AvWx Pro
//
// Created by Grayson Bertaina on 9/21/20.
//
import UIKit
class WxViewController: UIViewController, UITextFieldDelegate, WeatherManagerDelegate {
var weatherManager = WeatherManager()
#IBOutlet weak var stationSearch: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
weatherManager.delegate = self
stationSearch.delegate = self
}
#IBAction func searchPressed(_ sender: Any) {
print(stationSearch.text!)
stationSearch.endEditing(true)
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
print(stationSearch.text!)
stationSearch.endEditing(true)
return true
}
func textFieldDidEndEditing(_ textField: UITextField) {
if let station = stationSearch.text {
weatherManager.fetchWeather(stationICAO: station)
}
stationSearch.text = ""
}
func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
if stationSearch.text != "" {
return true
} else {
stationSearch.placeholder = "Type an ICAO"
return false
}
}
func didUpdateWeather(_ weatherManager: WeatherManager, weather: WeatherModel) {
print(weather.flightConditions)
}
func didFailWithError(error: Error) {
print(error)
}
}
//
// WeatherManager.swift
// AvWx Pro
//
// Created by Grayson Bertaina on 9/21/20.
//
import Foundation
protocol WeatherManagerDelegate {
func didUpdateWeather(_ weatherManager: WeatherManager, weather: WeatherModel)
func didFailWithError(error: Error)
}
struct WeatherManager {
let weatherURL = "https://avwx.rest/api/metar/"
var delegate : WeatherManagerDelegate?
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 {
self.delegate?.didFailWithError(error: error!)
return
}
if let safeData = data {
if let weather = self.parseJSON(safeData) {
self.delegate?.didUpdateWeather(self, weather: weather)
}
}
}
task.resume()
print(urlString)
}
}
func parseJSON(_ weatherData: Data) -> WeatherModel? {
do {
let decoder = JSONDecoder()
let decodedData = try decoder.decode(WeatherData.self, from: weatherData)
let clouds = decodedData.clouds
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?.value ?? 999
let visibilityValue = decodedData.visibility?.value ?? 0
let flightRulesValue = decodedData.flight_rules ?? "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)
return weather
} catch {
delegate?.didFailWithError(error: error)
return nil
}
}
}
//
// 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 station: String?
}
struct Clouds: Codable {
let type: String
let altitude: Int
}
struct WindSpeed: Codable {
let value: Int
}
struct WindGust: Codable {
let value: Int
}
struct WindDirection: Codable {
let value: Int
}
struct Visibility: Codable {
let value: Int
}
Thanks again.
First, on WeatherManager, declare your delegate as weak to avoid reference cycle
weak var delegate : WeatherManagerDelegate?
Second, after you decode the data, you have to call the delegate and pass the data, in this case,the WeatherModel you just created using one of your delegate methods
do {
let decoder = JSONDecoder()
let decodedData = try decoder.decode(WeatherData.self, from: weatherData)
let clouds = decodedData.clouds
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?.value ?? 999
let visibilityValue = decodedData.visibility?.value ?? 0
let flightRulesValue = decodedData.flight_rules ?? "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)
delegate?.didUpdateWeather(self, weather: weather)
return weather
} catch {
delegate?.didFailWithError(error: error)
return nil
}
On ReportViewController, assign self as your WeatherManagerDelegate on viewDidLoad(), then you have to implement the delegate function didUpdateWeather by updating your labels with corresponding values -- which you already started
class ReportViewController: UIViewController, WeatherManagerDelegate {
var weatherManager = WeatherManager()
#IBOutlet weak var flightRulesTitleLabel: UILabel!
#IBOutlet weak var flightRulesValueLabel: UILabel!
#IBOutlet weak var visibilityValueLabel: UILabel!
#IBOutlet weak var altimeterValueLabel: UILabel!
#IBOutlet weak var cloudsTitleLabel: UILabel!
#IBOutlet weak var cloudsType1Label: UILabel!
#IBOutlet weak var cloudsAltitude1Label: UILabel!
#IBOutlet weak var cloudsType2Label: UILabel!
#IBOutlet weak var cloudsAltitude2Label: UILabel!
#IBOutlet weak var cloudsType3Label: UILabel!
#IBOutlet weak var cloudsAltitude3Label: UILabel!
#IBOutlet weak var windGTextLabel: UILabel!
#IBOutlet weak var windSpeedValueLabel: UILabel!
#IBOutlet weak var windGustValueLabel: UILabel!
#IBOutlet weak var windFromTextLabel: UILabel!
#IBOutlet weak var windDirectionValueLabel: UILabel!
#IBOutlet weak var remarksValueLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
weatherManager.delegate = self
}
func didUpdateWeather(_ weatherManager: WeatherManager, weather: WeatherModel) {
DispatchQueue.main.async {
self.flightRulesValueLabel.text = weather.flightRules
self.cloudsType1Label.text = weather.lowestCloudsType
}
}

How do I pass Json Data from one class to another?

Can someone tell what could I do?
I have a class named RequestManager where i have the URLSession and inside of it, a constant where I store the Data from the server.
import Foundation
class RequestManager {
func fetchWeather(cityName: String,completionHandler: #escaping ([String]) -> Void){
let weatherURL = "https://api.openweathermap.org/data/2.5/weather?q=\(cityName)&appid=55dbb1b10e9f55181ad910227f1460ae&units=metric"
let objectURL = URL(string: weatherURL)
let task = URLSession.shared.dataTask(with: objectURL!, completionHandler: {(data,reponse,error)in
if error != nil{
print(error!)
} else{
do{
let json = try JSONDecoder().decode(CityWeatherInfo.self, from: data!)
print(json)
let saveData: WeatherModel = WeatherModel(name: json.name,
temp: json.main.temp, feelsLike: json.main.feelsLike,
tempMin: json.main.tempMin, tempMax: json.main.tempMax,
main: json.weathers[0].main, description: json.weathers[0].main)
print(saveData)
} catch{
print("error")
}
}
})
task.resume()
}
}
I run the app and get this in console when I ask for the server data:
CityWeatherInfo(name: "Paris", main: Evaluación_Autofin_México.Main(temp: 20.3, feelsLike: 18.41,
tempMin: 18.0, tempMax: 21.67), weathers: [Evaluación_Autofin_México.Weather(main: "Clouds",
description: "broken clouds")])
WeatherModel(name: "Paris", temp: 20.3, feelsLike: 18.41,
tempMin: 18.0, tempMax: 21.67, main: "Clouds", description: "Clouds")
I need to paste this info into a "WeatherViewDetailController" labels, but I can't enter to the "let saveData" from RequestManager.
class WeatherDetailViewController: UIViewController {
var weatherPresenter: WeatherDetailPresenter?
public var cityName: String?
let request = RequestManager()
#IBOutlet weak var closeButton: UIButton!
#IBOutlet weak var cityImage: UIImageView!
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var mainLabel: UILabel!
#IBOutlet weak var descriptionLabel: UILabel!
#IBOutlet weak var tempLabel: UILabel!
#IBOutlet weak var feelsLikeLabel: UILabel!
#IBOutlet weak var tempMinLabel: UILabel!
#IBOutlet weak var tempMaxLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
weatherPresenter = WeatherDetailPresenter(view: self)
weatherPresenter?.retriveWeatherByCity(cityName: self.cityName ?? "")
self.view.backgroundColor = UIColor(red: 56/255.0, green: 110/255.0, blue: 185/255.0, alpha: 1.0)
self.closeButton.tintColor = UIColor(red: 0/255.0, green: 20/255.0, blue: 20/255.0, alpha: 1)
}
#IBAction func closeAction(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
}
}
extension WeatherDetailViewController: WeatherDetailView {
func showWeatherSuccessful() {
print("Success")
}
func showWeatherFailure() {
print("Failure")
}
}
Update your fetch data with completion
func fetchWeather(cityName: String,completionHandler: #escaping (WeatherModel?) -> Void){
let weatherURL = "https://api.openweathermap.org/data/2.5/weather?q=\(cityName)&appid=55dbb1b10e9f55181ad910227f1460ae&units=metric"
let objectURL = URL(string: weatherURL)
let task = URLSession.shared.dataTask(with: objectURL!, completionHandler: {(data,reponse,error)in
if error != nil{
print(error!)
} else{
do{
let json = try JSONDecoder().decode(CityWeatherInfo.self, from: data!)
print(json)
let saveData: WeatherModel = WeatherModel(name: json.name,
temp: json.main.temp, feelsLike: json.main.feelsLike,
tempMin: json.main.tempMin, tempMax: json.main.tempMax,
main: json.weathers[0].main, description: json.weathers[0].main)
print(saveData)
completionHandler(saveData)
} catch{
completionHandler(nil)
print("error")
}
}
})
task.resume()
}
How to use
class WeatherDetailViewController: UIViewController {
var weatherPresenter: WeatherDetailPresenter?
public var cityName: String?
let request = RequestManager()
override func viewDidLoad() {
super.viewDidLoad()
request.fetchWeather(cityName: "", completionHandler: { [weak self] weatherModel in
// here you get object and you can set labels
self?.tempMinLabel.text = weatherModel.tempMin
self?. tempMaxLabel.text = weatherModel.tempMax
//....
})
}
}

How can I passing data UIViewContoller from UIView in swift3

How can i passing data uiviewController from uiview
I am Using function but it was not working
protocol name is startcalldelegate and function name is startcall
UIView Code
protocol StartCallDelegate: class {
func startCall(localNickname :String, remoteNickname :String)}
class CardView: UIView {
let managedObjectContext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
weak var delegate: CardViewDelegate?
weak var socketdelegate: StartCallDelegate?
#IBOutlet weak var UserPhoto: UIImageView!
#IBOutlet weak var UserNickName: UILabel!
#IBOutlet weak var UserAge: UILabel!
#IBOutlet weak var UserPeople: UILabel!
var localNickname: String = ""
var remoteNickname: String = ""
#IBAction func SendMessage(_ sender: Any) {
print("SendMessage")
//print(localNickName)
//print(UserNickName.text!)
}
#IBAction func SendVideoCall(_ sender: Any) {
print("SendVideoCall")
let entityDescription = NSEntityDescription.entity(forEntityName: "Profile", in: managedObjectContext)
let request = NSFetchRequest<NSFetchRequestResult>()
request.entity = entityDescription
do {
let objects = try managedObjectContext.fetch(request)
if objects.count > 0 {
let match = objects[0] as! NSManagedObject
localNickname = match.value(forKey: "nick") as! String
} else {
print("Nothing founded")
}
} catch {
print("error")
}
remoteNickname = UserNickName.text!
socketdelegate?.startCall(localNickname: localNickname, remoteNickname: remoteNickname)
delegate?.VideoChatSegue()
}
}
UIViewcontroller Code
class ViewController: UIViewcontroller, StartCallDelegate {
var localNickname: String = ""
var remoteNickname: String = ""
override func viewDidLoad() {
super.viewDidLoad()
print(localNickname)
print(remoteNickname)
}
func startCall(localNickname: String, remoteNickname: String) {
print("Action startcall func")
self.localNickname = localNickname
self.remoteNickname = remoteNickname
}
startCall func not working
You need to define delegate in viewcontroller' ViewDidLoad
let objOardView = CardView() // this is only test purpose
objOardView.socketdelegate = self

Resources