kampbell411 kampbell411 - 7 months ago 151
Swift Question

Passing custom data with map pin segue

I've been having trouble figuring out how to pass a custom variable in a map pin to another view controller in Swift. I know that passing the coordinates, title, and subtitle are available when you addAnnotation. I would like to try and pass a custom variable but hidden. Is there such a thing? Below I am getting the users location, mapping it, dropping a pin of a couple locations nearby with annotations which goes to another view controller and passes just the title and subtitle. Any insight is greatly appreciated.

import UIKit
import MapKit
import CoreLocation

class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {

var mappedCity = String()
var mappedState = String()

var manager = CLLocationManager()
var annotation:MKAnnotation!
var error:NSError!
var pointAnnotation:MKPointAnnotation!
var pinAnnotationView:MKPinAnnotationView!
var selectedAnnotation: MKPointAnnotation!

private var mapChangedFromUserInteraction = false

@IBOutlet var mapView: MKMapView!

override func viewDidLoad() {
super.viewDidLoad()

self.mapView.delegate = self
self.navigationItem.titleView = searchController.searchBar
self.definesPresentationContext = true


if CLLocationManager.locationServicesEnabled(){
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()

}

}


func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

let userLocation:CLLocation = locations[0]
let latitude = userLocation.coordinate.latitude
let longitude = userLocation.coordinate.longitude

let latDelta:CLLocationDegrees = 0.05
let lonDelta:CLLocationDegrees = 0.05
let span:MKCoordinateSpan = MKCoordinateSpanMake(latDelta, lonDelta)
let location:CLLocationCoordinate2D = CLLocationCoordinate2DMake(latitude, longitude)
let region:MKCoordinateRegion = MKCoordinateRegionMake(location, span)

self.mapView.setRegion(region, animated: true)
self.mapView.showsUserLocation = true

CLGeocoder().reverseGeocodeLocation(userLocation) { (placemarks, error) in

if (error != nil){

print(error)

}else {

if let p = placemarks?[0]{

let locality = p.locality ?? ""
let administrativeArea = p.administrativeArea ?? ""


self.mappedCity = String(locality)
self.mappedState = String(administrativeArea)

self.parseJSON("\(locality)", state: "\(administrativeArea)")
}

}



}
self.manager.stopUpdatingLocation()
}


func parseJSON(city: String, state: String){
let passedCity = city
let passedState = state
let escapedCity = passedCity.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())!
let escapedState = passedState.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())!

let url = NSURL(string:"http://www.API.com/api.php?city=\(escapedCity)&stateAbv=\(escapedState)")!

let session = NSURLSession.sharedSession()

let task = session.dataTaskWithURL(url) { (items, response, error) -> Void in

if error != nil {

print(error)


}else {


if let items = items {


do {
let jsonResult = try NSJSONSerialization.JSONObjectWithData(items, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary

if jsonResult.count > 0 {

if let datas = jsonResult["data"] as? NSArray{

for data in datas{

if let title = data["title"] as? String {

if let street = data["street"] as? String {

if let city = data["city"] as? String {

if let stateAbv = data["stateAbv"] as? String {

if let zip = data["zip"] as? String {

self.geoAddress("\(title)", street: "\(street)", city: "\(city)", state: "\(stateAbv)", zip: "\(zip)")


}
}
}

}

}

}
}

}
} catch{}


}


}

}

task.resume()

}


func geoAddress(title: String, street: String, city: String, state: String, zip: String){
let storeName = "\(title)"
let location = "\(street) \(city) \(state) \(zip)"
let geocoder = CLGeocoder();
geocoder.geocodeAddressString(location, completionHandler: {(placemarks: [CLPlacemark]?, error: NSError?) -> Void in
if (error != nil) {
print("Error \(error!)")
} else if let placemark = placemarks?[0] {

let coordinates:CLLocationCoordinate2D = placemark.location!.coordinate

let pointAnnotation:MKPointAnnotation = MKPointAnnotation()
pointAnnotation.coordinate = coordinates
pointAnnotation.title = storeName
pointAnnotation.subtitle = location

self.mapView.addAnnotation(pointAnnotation)

}
})
}


private func mapViewRegionDidChangeFromUserInteraction() -> Bool {
let view: UIView = self.mapView.subviews[0] as UIView
// Look through gesture recognizers to determine whether this region change is from user interaction
if let gestureRecognizers = view.gestureRecognizers {
for recognizer in gestureRecognizers {
if( recognizer.state == UIGestureRecognizerState.Began || recognizer.state == UIGestureRecognizerState.Ended ) {
return true
}
}
}
return false
}

func mapView(mapView: MKMapView, regionWillChangeAnimated animated: Bool) {
mapChangedFromUserInteraction = mapViewRegionDidChangeFromUserInteraction()
if (mapChangedFromUserInteraction) {
// user changed map region

}
}

func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
if (mapChangedFromUserInteraction) {
// user changed map region
let center = mapView.centerCoordinate

let mapLatitude = center.latitude
let mapLongitude = center.longitude


let locationmove = CLLocation(latitude: mapLatitude, longitude: mapLongitude)
CLGeocoder().reverseGeocodeLocation(locationmove) { (placemarks, error) in

if (error != nil){

print(error)

}else {

if let p = placemarks?[0]{

let locality = p.locality ?? ""
let administrativeArea = p.administrativeArea ?? ""


self.mappedCity = String(locality)
self.mappedState = String(administrativeArea)
self.parseJSON("\(locality)", state: "\(administrativeArea)")
}

}

}
}
}



func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
}

let reuseId = "pin"
var pinView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) as? MKPinAnnotationView
if pinView == nil {
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView?.animatesDrop = false
pinView?.canShowCallout = true
pinView?.draggable = true
pinView?.pinTintColor = UIColor.greenColor()
let rightButton: AnyObject! = UIButton(type: UIButtonType.DetailDisclosure)
pinView?.rightCalloutAccessoryView = rightButton as? UIView
}
else {
pinView?.annotation = annotation
}

return pinView
}

func mapView(mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
if control == view.rightCalloutAccessoryView {
selectedAnnotation = view.annotation as? MKPointAnnotation
performSegueWithIdentifier("Details", sender: self)
}
}

func mapView(mapView: MKMapView, annotationView view: MKAnnotationView, didChangeDragState newState: MKAnnotationViewDragState, fromOldState oldState: MKAnnotationViewDragState) {
if newState == MKAnnotationViewDragState.Ending {
let droppedAt = view.annotation?.coordinate
print(droppedAt)
}
}

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

if (segue.identifier == "Details"){
let myDetails = segue.destinationViewController as! DetailViewController
myDetails.mytitle = selectedAnnotation.title
myDetails.mysubtitle = selectedAnnotation.subtitle

}

}


func updateSearchResultsForSearchController(searchController: UISearchController) {


}


}

Answer

Subclass the "MKPointAnnotation" class and add your custom property in it.

class MyAnnotation : MKPointAnnotation {
    var customProperty : String?
}

And you can use MyAnnotation instead of MKPointAnnotation. Like following

 let pointAnnotation:MyAnnotation = MyAnnotation()
 pointAnnotation.coordinate = coordinates
 pointAnnotation.title = storeName
 pointAnnotation.subtitle = location
 pointAnnotation.customProperty = "your value"
 self.mapView.addAnnotation(pointAnnotation)