I'm struggling with passing data from a map pin to a new vc.
Scenario
Map pin data (name, subtitle & coordinates) are currently being read from a JSON file. Map pins are dropped, when map pin has been clicked a new view will open and display the corresponding title and subtitle and some other data in labels in a new vc.
I've been following this tutorial for extracting data from a JSON file.
Issue: I'm struggling to find a way to pass the data from the map pin to the labels.
I've done a previous project where I pass data from one textfield to a label.
Thank you very much!
EDIT:
I realised I didn't give any code.
newFeatureVC
// Callout accessory
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let identifier = "POIAnnotations"
if annotation is POIAnnotations {
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier)
if annotationView == nil {
annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
annotationView!.canShowCallout = true
let button = UIButton(type: .detailDisclosure)
annotationView!.rightCalloutAccessoryView = button
}
else {
annotationView!.annotation = annotation
}
return annotationView
}
return nil
}
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
if control == view.rightCalloutAccessoryView {
performSegue(withIdentifier: "showAnnotationInfo", sender: self)
}
}
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showAnnotationInfo" {
let destViewController = segue.destination as! ShopDetailViewController
}
}
POIAnnotations
This class is where variables stored for the name, subtitle and coordinates.
class POIAnnotations: NSObject, MKAnnotation {
var title: String?
var subtitle: String?
var coordinate: CLLocationCoordinate2D
init(title:String, subtitle:String, coordinate:CLLocationCoordinate2D) {
self.title = title
self.subtitle = subtitle
self.coordinate = coordinate
super.init()
}
class func fromJSON(_ json: [JSONValue]) -> POIAnnotations? {
// 1
var title: String
if let titleOrNil = json[1].string {
title = titleOrNil
} else {
title = ""
}
var subtitle: String
if let subtitleOrNil = json[2].string {
subtitle = subtitleOrNil
} else {
subtitle = ""
}
// 2
let latitude = (json[3].string! as NSString).doubleValue
let longitude = (json[4].string! as NSString).doubleValue
let coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
// 3
return POIAnnotations(title: title, subtitle: subtitle, coordinate: coordinate)
}
}
SecondVC
class ShopDetailViewController: UIViewController {
#IBOutlet weak var shopName: UILabel!
#IBOutlet weak var shopRating: UILabel!
#IBOutlet weak var cancelButton: UIBarButtonItem!
var shopNameData = "name"
var shopRatingData = "rating"
What I've already tried doing is the same way that I got the data from the JSON file in the POIAnnotations class.
I tried calling the fromJSON function then tried storing it in variable to display on the label. But I couldn't get my head around how to do it.
Use MKMapViewDelegate method to detect which pin is tapped and then display its data in view controller.
func mapView(MKMapView, didSelect: MKAnnotationView)
Related
I am struggling with my iOS code. The overall goal of the project is to show the pins on the map, I've tried multiple ways to make the pins appear on the map such as the below, I am not sure what I am doing wrong. The code runs fine, the pins are not appearing. I've made changes to my functions but seem to get the same error. Any insight on what I may be missing?
"import UIKit
import MapKit
class MapViewController: UIViewController, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
#IBOutlet weak var activityIndicator: UIActivityIndicatorView!
#IBOutlet weak var logout: UIBarButtonItem!
#IBOutlet weak var refresh: UIBarButtonItem!
#IBOutlet weak var pinDrop: UIBarButtonItem!
var studentLocation = [StudentInformation]()
var annotations = [MKPointAnnotation]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func viewDidAppear (_ animated: Bool) {
super.viewDidAppear(true)
getStudentPins()
}
#IBAction func refresh(_ sender: UIBarButtonItem) {
getStudentPins ()
}
#IBAction func logout(_ sender: UIBarButtonItem) {
self.activityIndicator.startAnimating()
UdacityClient.logout {
DispatchQueue.main.async {
self.dismiss(animated: true, completion: nil)
self.activityIndicator.stopAnimating()
}
}
}
#IBAction func addLocation(_ sender: Any) {
performSegue(withIdentifier: "addLocation", sender: nil)
}
func getStudentPins () {
self.activityIndicator.startAnimating()
UdacityClient.getStudentLocations() { locations, error in
self.mapView.removeAnnotations(self.annotations)
self.annotations.removeAll()
self.studentLocation = locations ?? []
for dictionary in locations ?? [] {
let latitude = CLLocationDegrees(dictionary.latitude ?? 0.0)
let longitude = CLLocationDegrees(dictionary.longitude ?? 0.0)
let coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
let firstName = dictionary.firstName
let lastName = dictionary.lastName
let mediaURL = dictionary.mediaURL
let annotation = MKPointAnnotation()
annotation.coordinate = coordinate
annotation.title = "\(firstName) \(lastName)"
annotation.subtitle = mediaURL
self.annotations.append(annotation)
}
DispatchQueue.main.async {
self.mapView.addAnnotations(self.annotations)
self.activityIndicator.stopAnimating()
}
}
}
private func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotation? {
let reuseId = "pin"
var pinView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseId) as? MKPinAnnotationView
if pinView == nil {
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView!.canShowCallout = true
pinView!.pinTintColor = .green
pinView!.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
}
else {
pinView!.annotation = annotation
}
return pinView?.annotation
}
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
if control == view.rightCalloutAccessoryView {
if let toOpen = view.annotation?.subtitle {
openLink(toOpen ?? "")
}
}
}
}"
They're called annotations in the MapKit and you should instantiate them like so:
let annotation = MKPointAnnotation()
then in the viewDidLoad() method just set the coordinates and add them to the map like:
annotation.coordinate = CLLocationCoordinate2D(latitude: 11.12, longitude: 12.11)
mapView.addAnnotation(annotation)
The numbers are your coordinates. Try by adding sample coordinates on the map first and then add all coordinates which you are getting from the client.
you can also add more information using:
annotation.title = "Your text here"
//You can also add a subtitle that displays under the annotation such as
annotation.subtitle = "One day I'll go here..."
I have a few moving parts in this one that I can't seem to stitch together, hopefully it is pretty straightforward.
Previous questions don't use a subclass and in this example there could be dozens of custom pins on the map and each pin passes specific variables to a new ViewController
Three Goals:
Add image to custom annotation (see code below)
I have a subclass named Capital, I would like to add the image in #1 and then create additional variables to hold values that will be passed to a new SecondViewController that includes (2) labels and a Picker View: for example label1 = "text1", label2 = "text2", and then grab a string from an array that contains multiple objects (i.e. the title for each row of the Picker)
Once the user taps on the callout button on the custom pin we push the ViewController to a new view controller named SecondViewController and assign the values of subclass Capital that are attached to the custom pin that was tapped to the new labels and picker view in the SecondViewController
Here is my code thus far:
Subclass named Capital.swift
import MapKit
import UIKit
class Capital: NSObject, MKAnnotation {
var title: String?
var coordinate: CLLocationCoordinate2D
var info: String
// here we would add the custom image in Goal #1
// here we would add the (2) values for label1 and label2 in Goal #2
// here we would add the array that contains multiple object in Goal #2
init(title: String, coordinate: CLLocationCoordinate2D, info: String) {
self.title = title
self.coordinate = coordinate
self.info = info
// add additional lines as needed
}
}
Here is my code for the ViewController.swift
import MapKit
import UIKit
class ViewController: UIViewController, MKMapViewDelegate {
#IBOutlet var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
let london = Capital(title: "London", coordinate: CLLocationCoordinate2D(latitude: 51.507222, longitude: -0.1275), info: "Home to the 2012 Summer Olympics.")
let oslo = Capital(title: "Oslo", coordinate: CLLocationCoordinate2D(latitude: 59.95, longitude: 10.75), info: "Founded over a thousand years ago.")
let paris = Capital(title: "Paris", coordinate: CLLocationCoordinate2D(latitude: 48.8567, longitude: 2.3508), info: "Often called the City of Light.")
let rome = Capital(title: "Rome", coordinate: CLLocationCoordinate2D(latitude: 41.9, longitude: 12.5), info: "Has a whole country inside it.")
let washington = Capital(title: "Washington DC", coordinate: CLLocationCoordinate2D(latitude: 38.895111, longitude: -77.036667), info: "Named after George himself.")
mapView.addAnnotations([london, oslo, paris, rome, washington])
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let identifier = "Capital"
if annotation is Capital {
if let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) {
annotationView.annotation = annotation
return annotationView
} else {
let annotationView = MKPinAnnotationView(annotation:annotation, reuseIdentifier:identifier)
annotationView.isEnabled = true
annotationView.canShowCallout = true
let btn = UIButton(type: .detailDisclosure)
annotationView.rightCalloutAccessoryView = btn
//annotationView.image = UIImage(named: "#imageLiteral(resourceName: ",pin,")")
return annotationView
}
}
return nil
}
Here we add the custom callout variables that are specific to the city that was pressed and push these to the SecondViewController
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
let capital = view.annotation as! Capital
let placeName = capital.title
let placeInfo = capital.info
//Add custom image + (2) labels + and the array that contains multiple objects to be passed to the Picker 'view in the SecondViewController
// Upon the User tapping the above button we push all the variables stored in Capital attached to the current city pin that was pressed to the new SecondViewController
// Send the View Controller to the SecondViewController programically
let SecondViewController = self.storyboard?.instantiateViewController(withIdentifier: "SecondViewController")
self.show(SecondViewController!, sender: nil)
}
Here is my code for the SecondViewController
import UIKit
class SecondViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
#IBOutlet weak var pickerView: UIPickerView!
var cityName = 0
//the values here are pulled from the custom pin that was pressed in the previous ViewController
var Array = ["object1 from custom pin","object2 from custom pin,","object3 from custom pin"]
#IBOutlet weak var label1: UILabel!
#IBOutlet weak var label2: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
pickerView.delegate = self
pickerView.dataSource = self
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return Array[row]
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return Array.count
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
#IBAction func submit(_ sender: Any) {
if (cityName == 0){
label1.text = "object1 from custom pin"
}
else if(cityName == 1){
label1.text = "object2 from custom pin"
}
else{
label1.text = "object3 from custom pin"
// continued...
}
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
cityName = row
}
}
Appreciate any help
It seems that you're very close. In calloutAccessoryControlTapped, you're get getting the place name and info. I'm assuming that's what you want to pass to the second view controller, so go ahead and do so before you show it:
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
let capital = view.annotation as! Capital
let placeName = capital.title
let placeInfo = capital.info
let secondViewController = sUIKeyInputUpArrowtoryboard!.instantiateViewController(withIdentifier: "SecondViewController") // I'm not sure why you're not just doing `storyboard.instantiateViewController(...); do you really have multiple storyboards floating around?
secondViewController.placeName = placeName
secondViewController.placeInfo = placeInfo
show(secondViewController, sender: self)
}
That presumes, of course, that your second view controller is has those placeName and placeInfo properties, e.g.
class SecondViewController {
var placeName: String!
var placeInfo: String!
override func viewDidLoad() {
// use placeName and placeInfo to populate UI controls as necessary
}
}
I confess, though, that your question has a ton of unrelated code that's hard to make sense of, so it's not clear precisely what you need to do. But the idea is clear, that calloutAccessoryControlTapped should
figure out what needs to get passed to the next view controller;
instantiate that view controller;
set the appropriate properties in that next view controller;
then show it; and
that second view controller should use whatever properties you set in the preceding view controller to configure it's UI.
Note, calloutAccessoryControlTapped in the first view controller cannot update the UI controls in the second view controller directly (since the controls for that view controller have not yet been hooked up to the outlets in the storyboard), but rather just passes whatever data that second view controller needs. Then that second view controller will configure its controls in its viewDidLoad.
Can any one help me to add different button action to the second annotation /pin (annotation2), Now the button do the same work in the two annotation pins how to do different work to each other . I'am using Swift3 in my project and this is my code . thanks
This is my code.
import UIKit
import MapKit
import CoreLocation
class MyAnnotation: MKPointAnnotation {
var uniqueId: Int!
}
class LocationViewController: UIViewController , MKMapViewDelegate , CLLocationManagerDelegate{
#IBOutlet weak var map: MKMapView!{
didSet{
map.delegate = self
}
}
#IBOutlet weak var locationInfo: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
let locations = CLLocationCoordinate2DMake(33.314627, 44.303500)
let location2 = CLLocationCoordinate2DMake(33.312149, 44.3024567)
let span = MKCoordinateSpanMake(0.02, 0.02)
let span2 = MKCoordinateSpanMake(0.02, 0.02)
let region = MKCoordinateRegionMake(locations, span)
let region2 = MKCoordinateRegionMake(location2, span2)
map.setRegion(region, animated: true)
map.setRegion(region2, animated: true)
let annotation = MyAnnotation()
//annotation.setCoordinate(location)
annotation.coordinate = locations
annotation.title = "Zaid Homes"
annotation.subtitle = "Hay aljameaa"
annotation.uniqueId = 1
map.addAnnotation(annotation)
let annotation2 = MyAnnotation()
//annotation.setCoordinate(location)
annotation2.coordinate = location2
annotation2.title = "Zaid "
annotation2.subtitle = "aljameaa"
annotation.uniqueId = 2
map.addAnnotation(annotation2)
//Showing the device location on the map
self.map.showsUserLocation = true;
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
var view = mapView.dequeueReusableAnnotationView(withIdentifier: "AnnotationView Id")
if view == nil{
view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "AnnotationView Id")
view!.canShowCallout = true
} else {
view!.annotation = annotation
}
view?.leftCalloutAccessoryView = nil
view?.rightCalloutAccessoryView = UIButton(type: UIButtonType.detailDisclosure)
return view
}
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
if (control as? UIButton)?.buttonType == UIButtonType.detailDisclosure {
mapView.deselectAnnotation(view.annotation, animated: false)
if let myAnnotation = view.annotation as? MyAnnotation {
if (myAnnotation.uniqueId == 1) {
performSegue(withIdentifier: "info", sender: view)
}
else {
performSegue(withIdentifier: "info2", sender: view)
}
}
}
}
}
The simplest way to know on which annotation you tap is using creating custom annotation class and adding annotation of it. So create one annotation class MyAnnotation child class of MKPointAnnotation and maintain one uniqueId with your multiple annotation.
class MyAnnotation: MKPointAnnotation {
var uniqueId: Int!
}
Now you need to add annotation of type MyAnnotation instead of MKPointAnnotation.
let annotation = MyAnnotation()
annotation.coordinate = locations
annotation.title = "Zaid Homes"
annotation.subtitle = "Hay aljameaa"
//Set uniqueId for annotation
annotation.uniqueId = 1
map.addAnnotation(annotation)
let annotation2 = MyAnnotation()
annotation2.coordinate = location2
annotation2.title = "Zaid "
annotation2.subtitle = "aljameaa"
//Set uniqueId for annotation
annotation2.uniqueId = 2
map.addAnnotation(annotation2)
Now check this uniqueId in calloutAccessoryControlTapped method on which annotation you tapped.
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
if (control as? UIButton)?.buttonType == UIButtonType.detailDisclosure {
mapView.deselectAnnotation(view.annotation, animated: false)
if let myAnnotation = view.annotation as? MyAnnotation {
if (myAnnotation.uniqueId == 1) {
performSegue(withIdentifier: "info1", sender: view)
}
else {
performSegue(withIdentifier: "info2", sender: view)
}
}
}
}
you can do this by creating two subClass of MKPointAnnotation and then in the delegate's method you can do this :
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
if view is subClass1 {
// do action for subclass 1
}
else if view is subClass2 {
// do action for subClass 2
}
}
Please let me know if this resolve your problem.
Update
you can make the implementation of you delegate more simpler like this exemple :
class ClassA:MKPointAnnotation{
func doActionWhenCalloutTapped(){
//do some action
}
}
class ClassB:ClassA{
override func doActionWhenCalloutTapped(){
//do some actions for annotation of type B
}
}
class ClassC:ClassA{
override func doActionWhenCalloutTapped(){
//do some actions for annotation of type C
}
}
func viewDidLoad(){
super.viewDidLoad()
let annotation = ClassB()
//annotation.setCoordinate(location)
annotation.coordinate = locations
annotation.title = "Zaid Homes"
annotation.subtitle = "Hay aljameaa"
map.addAnnotation(annotation)
let annotation2 = ClassC
//annotation.setCoordinate(location)
annotation2.coordinate = location2
annotation2.title = "Zaid "
annotation2.subtitle = "aljameaa"
map.addAnnotation(annotation2)
}
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
(view.annotation as! ClassA).doActionWhenCalloutTapped()
}
I'm building a application that allows people to post annotations on a map and you can click on the detail closure of the annotation and it loads a ViewController with the image and the subtitle information but when I try to load the image and subtitle in the viewDidLoad method of the detailVC it says it's nil
Here's my Annotation code:
extension ViewController: MKMapViewDelegate {
private struct Constants{
static let identifier = "pin"
static let LeftCalloutFrame = CGRect(x:0, y:0, width: 59, height: 59)
static let ShowPinSegueIdentifier = "showDetail"
}
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if let annotation = annotation as? PingAnnotation {
var view = mapView.dequeueReusableAnnotationViewWithIdentifier(Constants.identifier) as? MKPinAnnotationView
if view == nil {
view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: Constants.identifier)
view?.canShowCallout = true
} else {
view!.annotation = annotation
}
view!.calloutOffset = CGPoint(x: -5, y: 5)
view!.leftCalloutAccessoryView = UIImageView(frame: Constants.LeftCalloutFrame)
view!.rightCalloutAccessoryView = UIButton(type: .DetailDisclosure) as UIView
return view
}
return nil
}
func mapView(mapView: MKMapView, didSelectAnnotationView view: MKAnnotationView) {
if let thumbnailImageView = view.leftCalloutAccessoryView as? UIImageView {
if let pingAnnotation = view.annotation as? PingAnnotation{
thumbnailImageView.image = pingAnnotation.image
}
}
}
func mapView(mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
performSegueWithIdentifier(Constants.ShowPinSegueIdentifier, sender: view)
}
}
Annotation code:
class PingAnnotation: NSObject, MKAnnotation {
var coordinate : CLLocationCoordinate2D
var title: String?
var subtitle: String?
var image : UIImage?
init(coordinate: CLLocationCoordinate2D, title: String?, subtitle: String?, image: UIImage?) {
self.coordinate = coordinate
self.title = title
self.subtitle = subtitle
self.image = image
}
}
Detail VC Code:
import UIKit
class DetailPingVC: UIViewController {
var ping : PingAnnotation!
#IBOutlet var pingImage: UIImageView!
#IBOutlet var pingDesc: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
pingImage.image = ping.image //shows as nil when ran
pingDesc.text = ping.subtitle //shows as nil when ran
}
#IBAction func pingBtnPressed(sender: AnyObject) {
}
#IBAction func backBtnPressed(sender: AnyObject) {
dismissViewControllerAnimated(true, completion: nil)
}
}
EDIT:
I tried using prepareForSegue but the values still come out nil
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let destViewController: DetailPingVC = segue.destinationViewController as! DetailPingVC
destViewController.pingImage.image = ping.image
destViewController.pingDesc.text = ping.subtitle
}
Got it! Basically what I did was add a variable of type string and a variable of type UIImage to the DetailVC and then my prepareForSegue in my viewController looks as so:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let destViewController: DetailPingVC = segue.destinationViewController as! DetailPingVC
destViewController.descText = postTextField.text!
destViewController.detailImage = pickImage.image!
}
then in the viewDidLoad of the Detail VC you set the Outlets to the variables you set up earlier.
I have a mapView with a custom annotation. I also added a button to this but is there a way to see on which annotation the button was pressed?
So the post to the console should not only be "Disclosure Pressed!". I would need something like "Disclosure Pressed! info(X).subtitle" to see the user taped info1 or info2.
Here is the code:
import UIKit
import MapKit
class ViewController: UIViewController, MKMapViewDelegate {
#IBOutlet weak var Map: MKMapView!
class CustomPointAnnotation: MKPointAnnotation {
var imageName: String!
}
#IBAction func btpressed(sender: AnyObject) {
}
override func viewDidLoad() {
super.viewDidLoad()
//1
var lat1:CLLocationDegrees = 40.748708
var long1:CLLocationDegrees = -73.985643
var latDelta1:CLLocationDegrees = 0.01
var longDelta1:CLLocationDegrees = 0.01
var span1:MKCoordinateSpan = MKCoordinateSpanMake(latDelta1, longDelta1)
var location1:CLLocationCoordinate2D = CLLocationCoordinate2DMake(lat1, long1)
var region1:MKCoordinateRegion = MKCoordinateRegionMake(location1, span1)
Map.setRegion(region1, animated: true)
var info1 = CustomPointAnnotation()
info1.coordinate = location1
info1.title = "Test Title1!"
info1.subtitle = "Subtitle1"
info1.imageName = "1.png"
Map.addAnnotation(info1)
//2
var lat2:CLLocationDegrees = 41.748708
var long2:CLLocationDegrees = -72.985643
var latDelta2:CLLocationDegrees = 0.01
var longDelta2:CLLocationDegrees = 0.01
var span2:MKCoordinateSpan = MKCoordinateSpanMake(latDelta2, longDelta2)
var location2:CLLocationCoordinate2D = CLLocationCoordinate2DMake(lat2, long2)
var region2:MKCoordinateRegion = MKCoordinateRegionMake(location2, span2)
var info2 = CustomPointAnnotation()
info2.coordinate = location2
info2.title = "Test Title2!"
info2.subtitle = "Subtitle2"
info2.imageName = "2.png"
Map.addAnnotation(info2)
}
func mapView(mapView: MKMapView!, annotationView: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
if control == annotationView.rightCalloutAccessoryView {
println("Disclosure Pressed!")
}
}
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
if !(annotation is CustomPointAnnotation) {
return nil
}
let reuseId = "test"
var anView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId)
if anView == nil {
anView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
anView.canShowCallout = true
anView.rightCalloutAccessoryView = UIButton.buttonWithType(.InfoDark) as UIButton
var imageview = UIImageView(frame: CGRectMake(0, 0, 10, 10))
imageview.image = UIImage(named: "1.png")
anView!.leftCalloutAccessoryView = imageview
} else {
anView.annotation = annotation
}
//Set annotation-specific properties **AFTER**
//the view is dequeued or created...
let cpa = annotation as CustomPointAnnotation
anView.image = UIImage(named:cpa.imageName)
return anView
}
}
I've already tried something like:
if control == annotationView.rightCalloutAccessoryView {
println("Disclosure Pressed!" \(self.subtitle))
}
In the calloutAccessoryControlTapped delegate method, self is not the annotation whose callout accessory view was tapped.
self refers to the instance of the class the method is contained in (i.e. an instance of ViewController). The other issue is that in the println, you put the variable reference outside the quotes instead of inside.
The delegate method gives you a reference to the annotation view: the annotationView argument.
The annotation view contains a reference to the annotation: annotationView.annotation.
However, please note your delegate method declaration differs slightly from the documented one (annotationView argument has a local name view and other arguments are marked as optional with the ! suffix).
It's better to use the documented declaration even though your version will technically still work.
Complete example below also shows how to check if the annotation is one of your custom objects and how to access the custom property:
func mapView(mapView: MKMapView!, annotationView view: MKAnnotationView!,
calloutAccessoryControlTapped control: UIControl!) {
if control == view.rightCalloutAccessoryView {
println("Disclosure Pressed! \(view.annotation.subtitle)")
if let cpa = view.annotation as? CustomPointAnnotation {
println("cpa.imageName = \(cpa.imageName)")
}
}
}
Side note:
Since you've set the leftCalloutAccessoryView to a UIImageView, tapping on it will not call calloutAccessoryControlTapped because it is only called for views that are subclasses of UIControl. UIImageView is not a subclass of UIControl. If you need to detect taps on the left accessory, create a custom UIButton (and set its image) instead of a UIImageView.