Properties of custom Annotation don't visible in delegate methods - ios

I have many custom annotations to whom I gave the property (NameTable and ID). I set this property before AddAnnotation the moment of creation, but these property in the delegate methods are no longer visible. I have multiple annotation associated with elements of tables taken from a database. How can I make them visible in the delegate methods?
- (void)viewDidLoad
{
//......
for(int i=0; i<6; i++){ //loop for create multiple annotations
AnnotationCustom *annotationIcone =[[AnnotationCustom alloc]initWithCoordinates:coord
title:self.myTable.title subTitle:self.myTable.address];
annotationIcone.nameTable = [NSString stringWithFormat:#"%#", self.myTableName];
annotationIcone.ID = i+1;
[self.mapView addAnnotation: annotationIcone;
//.....
}
But in the delegate methods:
(MKAnnotationView *)mapView:(MKMapView *)mapview viewForAnnotation:(id
<MKAnnotation>)annotation
{
NSLog(#"The name of table is:#"%#", annotation.nameTable);
//property 'nameTable' not found on object of type '_strong id <MKAnnotation>
NSLog (#The name of table is:#%#", annotation.ID);
//property 'ID' not found on object of type '_strong id <MKAnnotation>
//......
}
In another method:
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view{
NSLog(#"The name of table is %#", self.myTableName);
// here I get the name of last table open and not the name of table selected
}

In viewForAnnotation, you need to tell the compiler that the annotation is actually an AnnotationCustom object.
So you first need to do this:
AnnotationCustom *annotationCustom = (AnnotationCustom *)annotation;
and then try to access the nameTable property..
In the didSelectAnnotationView method, if what you want is to get the nameTable value of the annotation selected you need to do the following:
AnnotationCustom *annotationCustomSelected = (AnnotationCustom *)view.annotation;
NSLog(#"table name of annotation selected: %#", annotationCustomSelected.nameTable);

Related

Updating annotation's tag value without removing & readding annotations in mapview

I have a requirement where I need to update my all annotations tags after removing every annotation.
You may be asking why not you are using removeAnnotations & addAnnotation?
The answer is, the no. of pins are really huge (~3000 for each polygon). So removing all annotations & readding those once again make a really annoying blink on the map. So I tried the following code:
-(void)deletePin
{
[MyMapView deselectAnnotation:currentAnnotationView.annotation animated:NO];
//currentAnnotationView is the selected annotationView
[self.arrAreaPin removeObjectAtIndex:currentAnnotationView.tag];
//arrAreaPin holds all pin's properties(tag, title, pin color, etc)
[MyMapView removeAnnotation:currentAnnotationView.annotation];
if (currentAnnotationView.tag<self.arrAreaPin.count)
{
NSUInteger index = 0;
for (id<MKAnnotation>annotation in MyMapView.annotations)
{
if (![annotation isKindOfClass:[MKUserLocation class]])
{
MyMapAnnotation *myAnn = (MyMapAnnotation *)annotation; //MyMapAnnotation is the custom MKAnnotation with some added properties like locationType(I stored the array index in it)
myAnn.locationType = index; //Updating with array index after deleting a pin
MKAnnotationView *annView = [MyMapView viewForAnnotation: annotation];
NSLog(#"Before updating Annotation tag: %lu",annView.tag);
annView.tag = index;
NSLog(#"After updating Annotation tag: %lu",(unsigned long)annView.tag);
}
index++;
}
}
}
But it looks like the way the for loop picks the annotations from mapview doesn't match with the order of arrAreaPin array. So when I'm printing the tag value of annotationView before & after updating annonation tag it looks like :
Before updating Annotation tag: 0
After updating Annotation tag: 0
Before updating Annotation tag: 10
After updating Annotation tag: 1
Before updating Annotation tag: 16
After updating Annotation tag: 2
Before updating Annotation tag: 5
After updating Annotation tag: 3
Before updating Annotation tag: 17
After updating Annotation tag: 4
So basically its looks like the for loop is picking annotation randomly from map. Am I right?
Is it possible to update annotation's tag orderly? Thanks in advance.
The for in loop that you use processes the array elements in the order they are stored in the MyMapView.annotations array.
You said that you want them to be processed „orderly“. I assume that you want to process them in their tag order, which is obviously not the order the elements are stored in the array. So you had to sort them by tag order before you process them.
So my suggestion is to use something like (has been edited due to Poles comment below):
// Get your annotations (without the user location)
NSArray *myAnnotations = [MyMapView.annotations filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(MKAnnotation *annotation, NSDictionary *bindings) {
return ![annotation isKindOfClass:[MKUserLocation class]];
}]];
// Sort your annotations by their tag
NSArray *sortedAnnotations = [myAnnotations sortedArrayUsingComparator:^NSComparisonResult(MKAnnotation *a, MKAnnotation *b) {
MKAnnotationView *annViewA = [MyMapView viewForAnnotation: a];
MKAnnotationView *annViewB = [MyMapView viewForAnnotation: b];
return [[NSNumber numberWithInteger:annViewA.tag] compare:[NSNumber numberWithInteger:annViewB.tag]];
}];
// Update the tags
for (id<MKAnnotation>annotation in sortedAnnotations) {
MyMapAnnotation *myAnn = (MyMapAnnotation *)annotation;
myAnn.locationType = index;
MKAnnotationView *annView = [MyMapView viewForAnnotation: annotation];
NSLog(#"Before updating Annotation tag: %lu",annView.tag);
annView.tag = index;
NSLog(#"After updating Annotation tag: %lu",(unsigned long)annView.tag);
index++;
}

How to tell which button is being pressed in calloutAcessoryControlTapped?

I'm using MapKit and I have 2 callout accessories in my pins.
I'm trying to implement a button for updating the pin's title and one for deleting the pin.
Right now, anytime I press a button on the annotation, it only deletes the pin.
How do I get it to respond differently for the right button vs the left button?
-(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
id <MKAnnotation> annotation = [view annotation];
if ([annotation isKindOfClass:[MKPointAnnotation class]])
{
NSLog(#"Clicked");
if(view.rightCalloutAccessoryView){
[self.mapView removeAnnotation:annotation];
}
else{
float lat= annotation.coordinate.latitude;
float longitude = annotation.coordinate.longitude;
[self.mapView removeAnnotation:annotation];
MKPointAnnotation *pointAnnotation = [[MKPointAnnotation alloc] init];
pointAnnotation.title = _titleOut.text;
pointAnnotation.subtitle = _subtitle.text;
pointAnnotation.coordinate = CLLocationCoordinate2DMake(lat, longitude);
[self.mapView addAnnotation:pointAnnotation];
}
}
}
This line:
if(view.rightCalloutAccessoryView){
says essentially "if view.rightCalloutAccessoryView is not nil".
Since you are setting the right-side accessory on all annotation views, that if condition will always be true and so tapping either accessory will execute the code inside that if which is to remove the annotation.
Instead, you want to check what button or control was tapped in this specific case of the delegate method being called (not whether the view has a right-side accessory defined).
Fortunately, the delegate method passes exactly what control was tapped in the control parameter.
The control parameter can be directly compared against the view's right/left accessory view to tell which was tapped:
if (control == view.rightCalloutAccessoryView) {
Some unrelated points:
The latitude and longitude properties in annotations are of type CLLocationDegrees (aka double) which has higher precision than float so to avoid losing accuracy, use CLLocationDegrees or double:
CLLocationDegrees lat= annotation.coordinate.latitude;
The MKPointAnnotation allows you to change the title directly (it's not read-only like the default id<MKAnnotation>) so you don't need to remove and create a new annotation. It simplifies the code a bit:
-(void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control {
if ([view.annotation isKindOfClass:[MKPointAnnotation class]])
{
NSLog(#"Clicked");
if (control == view.rightCalloutAccessoryView) {
[self.mapView removeAnnotation:view.annotation];
}
else {
// Cast view.annotation as an MKPointAnnotation
// (which we know it is) so that compiler sees
// title is read-write instead of the
// default id<MKAnnotation> which is read-only.
MKPointAnnotation *pa = (MKPointAnnotation *)view.annotation;
pa.title = _titleOut.text;
pa.subtitle = _subtitle.text;
//If you want callout to be closed automatically after
//title is changed, uncomment the line below:
//[mapView deselectAnnotation:pa animated:YES];
}
}
}

How to get map annotation title in this method

i want to get annotation title & subtitle from this method.
what the way go get that.
-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view{
//NSString * title = [annotations title];
}
The view has an annotation property that you can use which will return the annotation you originally used when creating the view.

xcode - UIButton in mapView annotations w/ tags?

I've read most of the other questions here, as well as read a lot, but I'm not finding an answer.
I'm using this code to create the buttons
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation{
NSLog(#"called the MKAnnotView method, tag is: %i", self.tag);
static NSString *s = #"ann";
MKAnnotationView *pin = [mapView dequeueReusableAnnotationViewWithIdentifier:s];
if (!pin) {
pin = [[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:s];
pin.canShowCallout = YES;
pin.calloutOffset = CGPointMake(0, 0);
UIButton *button = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
button.tag=self.tag++;
[button addTarget:self
action:#selector(viewDetails:)
forControlEvents:UIControlEventTouchUpInside];
pin.rightCalloutAccessoryView = button;
}
return pin;
}
-(void) viewDetails: (id) sender {
UIButton *button = sender;
NSLog(#"viewDetails called with button.tag: %i",button.tag);
//[self performSegueWithIdentifier:#"detailView" sender:self];
}
I'm creating a variable amount of pins, in a specific order. When I create them, I get the expected output of "called the MKAnnotView method, tag is 0" then 1, 2, 3, etc.
The annotations are in a very specific order. Zeroth, first, second, so forth. I expect the buttons I created for each annotation to have a tag that fits their index, so that when I segue to the detailViewController, I know which item on the list needs to be pulled and the view populated.
That's not happening. The buttons are each getting randomly assigned tags that repeat. My last case had two tags with 3, and two with zero.
I cannot for the life of me understand why.
Any hints?
Based on comments to my question, the solution I came up with was implementing the following
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
self.tag = [self.annotArray indexOfObject:view.annotation];
NSLog(#"calloutAccessoryControlTapped: annotation = %i", self.tag);
[self performSegueWithIdentifier:#"ShowDetails" sender:self];
}
Whenever I create an annotation, I was already adding it to an annotArray property of this viewController for another use (as the view's built-in annotation array was not populating in a predictable manner)
my prepareForSegue method pulls self.tag and updates a property of the destinationViewController.

iOS trouble accessing property of MKAnnotation

I can't seem to access a custom MKAnnotation property inside of mapView:viewForAnnotation delegate method. As I understand it, the method takes annotations as values. I'm trying to target the properties of each annotation that gets passed in.
Code
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
//This actually returns a proper coordinate
NSLog(#"%f", annotation.coordinate.latitude);
//This gives me an error: Property 'annotationMarker' not found on object of type '__strong id<MKAnnotation>'
NSLog(#"%#", annotation.annotationMarker);
MKAnnotationView *testPin = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"current"];
testPin.image = [UIImage imageNamed:[[testArray objectAtIndex:1]annotationMarker]];
return testPin;
}
I thought maybe the custom property wasn't set correctly, but I'm able to log the property values for these annotations in other parts of the code.
Am I making some kind of syntax error? Does this delegate method strip out custom properties somehow?
You need to cast to your custom MKAnnotation-conformant class, e.g.
CustomAnnotation *customAnnotation = (CustomAnnotation *)annotation;
NSLog(#"%#", customAnnotation.annotationMarker);

Resources