Reputation: 1189
I am trying to construct a Map App that can receive user inputs of latitude and longitude coordinates that when entered, will place a pin on a map in a different tab. My FirstVC consists of a button "Add Locations" that segues to OtherVC which the user can input the coordinates. SecondVC consists of the MapView. My initial idea is to have a specific array of coordinates, and any new coordinates will be appended to this array. The execution is where I am lacking, because I am not sure how to transfer this array to the MapView. Here is what I have so far:
For the input of coordinates:
import UIKit
import CoreLocation
class OtherVC: UIViewController {
@IBOutlet weak var latitudeField: UITextField!
@IBOutlet weak var longitudeField: UITextField!
var coordinates = [CLLocationCoordinate2D]()
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func addToMap(_ sender: Any) {
let lat = Double(latitudeField.text!)
let long = Double(longitudeField.text!)
self.coordinates.append(CLLocationCoordinate2D(latitude: lat!, longitude: long!))
}
}
For the MapView:
import UIKit
import MapKit
class MapViewController: UIViewController, MKMapViewDelegate {
@IBOutlet weak var mapView: MKMapView!
var coordinates = [CLLocationCoordinate2D]() {
didSet {
// Update the pins
// Since it doesn't check for which coordinates are new, it you go back to
// the first view controller and add more coordinates, the old coordinates
// will get a duplicate set of pins
for (index, coordinate) in self.coordinates.enumerated() {
let annotation = MKPointAnnotation()
annotation.coordinate = coordinate
annotation.title = "Location \(index)"
mapView.addAnnotation(annotation)
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let identifier = "pinAnnotation"
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKPinAnnotationView
if annotationView == nil {
annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
annotationView?.canShowCallout = true
}
annotationView?.annotation = annotation
return annotationView
}
}
Upvotes: 4
Views: 532
Reputation: 16327
Generally speaking I only use the method of directly passing the data from one ViewController to the next if there is a parent child relationship and I can do it in prepareForSegue or in and unwind (child to parent). Otherwise I think its better to use the publisher subscriber model with Notification. When your coordinate changes you post a Notification:
NotificationCenter.default.post(name: NSNotification.Name("MapViewController.coordinate.updated"), object: self, userInfo: nil)
Now anyone who cares about MapViewController's coordinates changing can listen:
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(coordinateUpdated), name: NSNotification.Name("coordinate.updated"), object: nil)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
@objc private func coordinateUpdated( notification: Notification) {
if let source = notification.object as? MapViewController {
print(source.coordinates)
}
}
This makes the views loosely coupled and MapViewController doesn't need to care about who needs to be updated; the subscribers are responsible for registering themselves.
Upvotes: 1
Reputation: 20804
I think you need is get your second ViewController MapViewController
from your tabBarController and then pass the coordinates array, so in your addToMap Action replace with this
@IBAction func addToMap(_ sender: Any) {
let lat = Double(latitudeField.text!)
let long = Double(longitudeField.text!)
self.coordinates.append(CLLocationCoordinate2D(latitude: lat!, longitude: long!))
//here we pass the coordinate array to mapViewController
if let mapViewController = self.tabBarController?.viewControllers?[1] as? MapViewController
{
mapViewController.coordinates = self.coordinates
}
}
You need also add a navigation controller, like in the picture
I hope this helps you
Upvotes: 2