Olav Martinius Tomter
Olav Martinius Tomter

Reputation: 45

Unable to send coordinates from ViewController with mapKit to another viewController with delegate

I am new to Swift and iOS development. I have an issue where I have three viewControllers connected via a tab bar navigation controller. The first viewController is empty for now and not in use. In the secondViewController I update the UI with data from a weather API. In the thirdViewController I have a map. When I access the map I need the coordinates to update the url in the secondViewController.

What I'm trying to achieve is retrieving the current latitude and longitude in the thirdViewController (no problem), but I'm unable to send these values through a delegate in order to trigger the function in the secondViewController and thus update the variables in there. The delegate function in the secondViewController just doesn't get triggered. What am I doing wrong? Or is it even possible to do this way?

The code is as follows for both viewControllers:

secondViewController (this is where I need the values from the map in thirdViewController)

import UIKit

class SecondViewController: UIViewController, MapViewControllerDelegate {

    var forecastData: [ForecastData] = []
    var currentLat: String = "59.911166"
    var currentLon: String = "10.744810"
    
    @IBOutlet weak var tableView: UITableView!
    
    var weatherManager = WeatherManager()
    var mapViewController = ThirdViewController()
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        mapViewController.delegate = self
        weatherManager.delegate = self
        weatherManager.fetchWeather(latitude: currentLat, longitude: currentLon)
        tableView.backgroundView = UIImageView(image: UIImage(named: "background"))
        tableView.dataSource = self
        tableView.register(UINib(nibName: "WeatherCell", bundle: nil), forCellReuseIdentifier: "WeatherCell")
        
    }
    
    func viewDidAppear() {
        weatherManager.fetchWeather(latitude: currentLat, longitude: currentLon)
        
    }
    
    
    // THIS FUNCTION SHOULD BE TRIGGERED BUT DOESN'T
    
    func mapViewController(latitude: String, longitude: String) {
        currentLat = latitude
        currentLon = longitude
        print(currentLat)
        print(currentLon)
        print("DELEGATE METHOD TRIGGERED")
    }

}

//MARK: - WeatherManagerDelegate

extension SecondViewController: WeatherManagerDelegate {
    
    func didUpdateWeather(_ weatherManager: WeatherManager, weather: WeatherModel) {
        
        forecastData.append(ForecastData(timespan: "Nå", precipitation: "", tempOrWeather: "Temperatur", tempWeatherLabel: "\(weather.temperatureNow)" + " " + "\(weather.tempUnits)"))
        
        forecastData.append(ForecastData(timespan: "Neste Time", precipitation: "\(weather.precipitationNext1H)" + " " + "\(weather.precipUnits)", tempOrWeather: "vær", tempWeatherLabel: String(weather.conditionNext1H) ))
        
        forecastData.append(ForecastData(timespan: "Neste 6 timer", precipitation: "\(weather.precipitationNext6H)" + " " + "\(weather.precipUnits)", tempOrWeather: "vær", tempWeatherLabel: String(weather.conditionNext6H)))
        
        forecastData.append(ForecastData(timespan: "Neste 12 timer", precipitation: "", tempOrWeather: "vær",  tempWeatherLabel: String(weather.conditionNext12H)))
        
        DispatchQueue.main.async {
            self.tableView.reloadData()
        }
        
    }
    
    func didFailWithError(error: Error) {
        print(error)
    }
}

extension SecondViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return forecastData.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "WeatherCell", for: indexPath)
        as! WeatherCell
        cell.TimeframeLabel.text = forecastData[indexPath.row].TimeframeLabel
        cell.TempLabel.text = forecastData[indexPath.row].TempLabel
        cell.WeatherCodeLabel.text = forecastData[indexPath.row].WeatherCodeLabel
        cell.PrecipitationLabel.text = forecastData[indexPath.row].PrecipitationLabel
        return cell
    }
}

thirdViewController (this is where I try to pass the coordinates values through the delegate)

import UIKit
import MapKit
import CoreLocation

protocol MapViewControllerDelegate {
    func mapViewController(latitude: String, longitude: String)
}

class ThirdViewController: UIViewController, MKMapViewDelegate {
    
    var currentLat = ""
    var currentLon = ""
    @IBOutlet weak var mMapView: MKMapView!
    fileprivate let locationManager: CLLocationManager = CLLocationManager()
    var delegate: MapViewControllerDelegate?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        locationManager.requestWhenInUseAuthorization()
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.distanceFilter = kCLDistanceFilterNone
        locationManager.startUpdatingLocation()
        
        mMapView.showsUserLocation = true
               
        currentLat = String((locationManager.location?.coordinate.latitude)!)
        currentLon = String((locationManager.location?.coordinate.longitude)!)
        
        print(currentLat)
        print(currentLon)
        
        //delegate?.mapViewController(latitude: "TESTlon", longitude: "TESTlati")
    }
    
    override func viewDidAppear(_ animated: Bool) {
        updateWeatherView()
    }
    
    // THIS SHOULD TRIGGER THE DELEGATE FUNCTION IN SECOND VIEW CONTROLLER AND PASS THE DATA ALONG
    func updateWeatherView() {
        delegate?.mapViewController(latitude: "TESTlon", longitude: "TESTlati")
    }
    
}


I have tried different thing, but nothing seems to work, the delegate function in secondViewController just doesn't get triggered. Again, I am very new to this so maybe it's a simple thing. Thanks in advance for any help! Also, here is a screenshot of my storyboard if it can help:

Screenshot of storyboard

Upvotes: 1

Views: 106

Answers (1)

aheze
aheze

Reputation: 30516

As @Duncan C said, doing

var weatherManager = WeatherManager()
var mapViewController = ThirdViewController()

just creates a new instance of those view controllers -- these are completely unrelated to the ones you already have. Sure, if you do mapViewController.delegate = self, you are setting mapViewController's delegate... but mapViewController is not the view controller that you want.

To get the view controller that you want, you can access the tab bar controller's view controllers (these are automatically created for you when you make them in the storyboard), and pick the right one:

if 
    let viewControllers = self.tabBarController?.viewControllers, 
    viewControllers.count >= 3,
    let thirdViewController = viewControllers[2] as? ThirdViewController /// [2] because that's the third view controller in the array, which is the one you want
{
    thirdViewController.delegate = self
}

self.tabBarController could be nil, so you need to unwrap it. Then, you should make sure that there are more than 3 view controllers. Finally, you need to cast the view controller you need (self.tabBarController?.viewControllers[2]) to ThirdViewController. You can then set the delegate to that view controller.

Upvotes: 2

Related Questions