0
votes

I have populated several pins on a MapView using a JSON file. Each of these pins correctly display a callout with a title, subtitle, image and detailDisclosure button.

I am trying to create a segue between the MapView and a Detail View (arranged as a TableView) so that when users click the detailDisclosure button, they are brought to the Detail View screen.

The segue I have created works perfectly, however, I cannot figure out how to pass the data through. How can I successfully pass data through this segue so that it appears in the Detail View? Please see the relevant code below.

My segue code:

func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
    self.performSegue(withIdentifier: "toShowLocationDetail", sender: self)
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "toShowLocationDetail" {
        // I DON'T KNOW WHAT TO PUT IN HERE - I THINK THIS IS WHERE THE INFORMATION ABOUT THE DATA GOES
    }
}

I'm not sure if you will require this, but this is my ViewDidLoad method (which I have used to parse the JSON file and populate the annotations:

var locations = [Location]()

override func viewDidLoad() {
    super.viewDidLoad()

    // parse json
    if let locationJson = readLocation(){
        if let locationArray = locationJson["locations"] as? [[String:Any]]{
            for location in locationArray{
                locations.append(Location.init(locationInfo: location))
            }
            print(locations.count)
        }
    }
    // end parse json

    nearMeMap.delegate = self

    self.locationManager.delegate = self
    self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
    self.locationManager.requestWhenInUseAuthorization()
    self.locationManager.startUpdatingLocation()
    self.nearMeMap.showsUserLocation = true


    // Show annotation
    for location in locations {
        let annotation = MKPointAnnotation()
        annotation.title = location.name
        annotation.subtitle = location.type
        annotation.coordinate = CLLocationCoordinate2D(latitude: location.latitude, longitude: location.longitude)
        self.nearMeMap.addAnnotation(annotation)

    }

}

It is important to note that I already have a functional segue between a TableView and the DetailView. I am now wanting to allow users to access the same DetailView page through a MapView.

The variable set within the DetailView (which currently enables it to show the data from the TableView) is:

var location:Location!

EDIT: This is the Location.swift class:

class Location: NSObject {
    var id: String = ""
    var name: String = ""
    var type: String = ""
    var location: String = ""
    var image: String = ""
    var activity: String = ""
    var isVisited: Bool = false
    var rating: String = ""
    var latitude: Double = 0.0
    var longitude: Double = 0.0

    init(locationInfo:[String:Any]) {
        self.id = locationInfo["id"] as! String
        self.name = locationInfo["name"] as! String
        self.type = locationInfo["type"] as! String
        self.location = locationInfo["location"] as! String
        self.image = locationInfo["image"] as! String
        self.activity = locationInfo["activity"] as! String
        self.isVisited = locationInfo["isVisited"] as! Bool
        self.latitude = locationInfo["latitude"] as! Double
        self.longitude = locationInfo["longitude"] as! Double
    }

    public var coordinate: CLLocationCoordinate2D { get {
        let coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
        return coordinate
        }
    }

}
1
How do you determine which pin you tapped?nayem
I'm not sure that I have @nayem - where should this go? What would it look like?joshlorschy
You should go through these: link1, link2, link3nayem
Is this necessary? How would it solve my issue?joshlorschy

1 Answers

3
votes

You have to keep track of the selected Annotation. And then you can use the coordinate property of that annotation for passing to DetailView through your prepare(for:sender:) method.

var selectedAnnotation: MKPointAnnotation?

func mapView(mapView: MKMapView, didSelectAnnotationView view: MKAnnotationView) {
    self.selectedAnnotation = view.annotation as? MKPointAnnotation
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    let filteredLocations = locations.filter { (location) -> Bool in
        return (location.latitude == self.selectedAnnotation?.coordinate.latitude && location.longitude == self.selectedAnnotation?.coordinate.longitude)
    }
    let selectedLocation = filteredLocations.first
    if segue.identifier == "toShowLocationDetail" {
        let destinationViewController = segue.destination as! DetailView
        destinationViewController.location = selectedLocation
    }
}

And in your DetailView class make the location property optional like: var location: Location?