Is there a method (or any way) you can get the "index path" of the annotation inside the method:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation
What I want to do is get something inside an array according to the annotation. One of the methods I think that I want to copy is - tableView:cellForRowAtIndexPath: and use the "indexPath".
Searched a lot but not found any result. Or maybe I'm just bad at searching. Any reference will be greatly appreciated.
NSUInteger index = [mapView.annotations indexOfObject:annotation];
Since the underlying array is a mutable one, note that the index can change. This seems to be the closest indexPath like information you can get.
To answer my own question (this how it works for me):
I created an instance in the custom annotation and transferred the data there, then inside - mapView:viewForAnnotation: (I used custom pinView) I imported and created an instance of my CustomAnnotation and got the data from there.
[customAnnotation setSomething: data];
- mapView:viewForAnnotation:
{
pinView = [[[CustomPinView alloc] initWithAnnotation: annotation reuseIdentifier: PinIdentifier] autorelease];
}
- initWithAnnotation:reuseIdentifier:
{
CustomAnnotation *customAnnotation = (CustomAnnotation *)annotation;
[customAnnotation something];
}
Overkill for me but it gets the job done.
Related
In my application I have a MKMapView where several annotations are shown. The map rotates based on the heading of the device. To rotate the map the following statement is performed (called by the method locationManager: didUpdateHeading:)
self.navigationMapView.mapView.transform = CGAffineTransformMakeRotation(-heading);
where the heading (magnetic) is expressed in radians. What I noticed it's that even the annotations in the map rotate and I don't want it. I tried to fix it in the following method:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation{
static NSString *identifier = #"AnnotationViewIdentifier";
MKAnnotationView *av = [mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (av == nil) {
av = [[[MKPinAnnotationView alloc]initWithAnnotation:annotation reuseIdentifier:identifier] autorelease];
}
else{
av.annotation = annotation;
}
av.transform = CGAffineTransformMakeRotation(degreesToRadians(self.arController.currentHeading.magneticHeading));
av.canShowCallout = YES;
return av;
}
and I want to call this method from "didUpdateHeading:" but I really don't know how to do it. The TableView class has the reloadData function that calls the delegate method but here the things seem different. Any suggestions?!
Another question, my annotations on the map show the distance from the user, I would like to update them (distance label) as soon as the user change location. Any suggestions?!
So with a MKMapView having that be called properly is a little bit annoying. Essentially you have one of two options. Option 1: Create an array of the annotation on the screen and remove that from the map_view and then re-add them to the map_view. Essentially creating your own reload data function. Option 2: Do something simple such as
CGLocationCoordinate2D coordinate = map_view.center;
map_view.center = coordinate;
-- Essentially the point is to reset a property of the map causing it to redraw. However this option is not always going to work. Option 1 has a higher chance of working however that one can also fail, so if simply taking the annotations off and re-adding them causes nothing to happen then simply decreate the map and then recreate the map at the end of your map refresh function something like.
[my_map_view removeFromSuperView];
[my_map_view release];
my_map_view = nil;
my_map_view = [[MKMapView alloc] initWithFrame:CGRectMake(0,0,320,480)];
one of these options should work. I had to do option one for my solution however I know some people are lucky and option 2 works just as well.
:)
I have a really strange problem when trying to retrieve the properties of a selected annotation. Here is the short description of my problem:
I pass the first object of the selected annotations array to a new array as it's the only one I need (acc. to Apple doc, passing the selectedAnnotations array to a new array only selects the first object. But I did tried to pull the object directly from the selectedAnnotations array at index path 0 and it's the same problem).
Then I transform the object into a Custom annotation object (as this is what the object should be).
Afterwards I try to access the properties of my custom annotation temp object. Here is when everything breaks loose. NSLog of the object only shows memory address. Text property is null. So basically I can't access it.
I would appreciate any help on what am I doing wrong or what approach should I use.
Thank you kindly!
Here is the code:
-(void) mapView:(MKMapView *)aMapView didSelectAnnotationView:(MKAnnotationView *)view
{
if ([view isUserInteractionEnabled])
// NSLog(#"Tapped!!!");
{
NSArray* selectedAnnotation=mapView.selectedAnnotations;
CustomAnnotations *selectedAnn=[selectedAnnotation objectAtIndex:0];
NSLog(#"selected annotation text is %#", selectedAnn.text);
My custom annotation class has a coordinate and a text property and it's being placed on map with this code:
CustomAnnotations* commentAnnotation = [[[CustomAnnotations alloc] initWithLocation:mapView.userLocation.location.coordinate andTitle:#"comment" andText:text]autorelease];
[mapView addAnnotation:commentAnnotation];
Furthermore, the view for annotation has the following coding:
-(MKAnnotationView *) mapView:(MKMapView *) aMapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
MKAnnotationView *customAnnotation = (MKAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:#"pin"];
if(!customAnnotation)
{
customAnnotation = [[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"pin"]autorelease];
}
customAnnotation.centerOffset=CGPointMake(10, -30);
if ([annotation title]==#"comment")
{
customAnnotation.userInteractionEnabled=YES;
customAnnotation.image=[UIImage imageNamed:#"NewCommentsPin.png"];
}
return customAnnotation;
}
Any help would be much appreciated!
I figured out the problem: My custom annotation class was releasing the text in dealloc.
I still have a long way to go until I understand when to release and when not to but one step at a time!:)
Here is your release cheat sheet.
When you create an object, and it has any of the words new, alloc,
copy or retain in the constructor then you own it and you have
to release it if you do not need the reference any more.
I've subclassed MKAnnotation so that i can assign objects to each annotation, this is so that when the rightCalloutAccessoryView is clicked i can push a navigation controller with the object passed to it and display the objects data in another view.
This all works great apart from one thing, i've extended upon initWithCoordinate like so:
-(id)initWithCoordinate:(CLLocationCoordinate2D)coord andObject:(NSManagedObject *)object {
[self setPlace:object];
coordinate = coord;
title = [place valueForKey:#"name"];
subtitle = [place valueForKey:#"address"];
return self;
}
Although everything is working great i'm recieving the warning:
NO '-initWithCoordinate:andObject:' method found
Which means i'm doing something wrong somewhere, what is the correct way to go about adding upon initWithCoorinate?
Put the prototype -(id)initWithCoordinate:(CLLocationCoordinate2D)coord andObject:(NSManagedObject *)object in .h file.
Trying to figure out this MKPolygon working. I've created a whole heap MKMapPoints and placed them into an array. Then I make a Polygon out of them with:
[MKPolygon polygonWithPoints:pointArr count:sqlite3_column_int(countStatement, 0)];
and add that to an Array for retrieval later.
Later I loop through the array and add each object (MKPolygon) to the map with:
[mapView addOverlay:[overlays objectAtIndex:i]];
And this according to logs works fine.
I then implement mapView: viewForOverlay: like so
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay {
MKOverlayView *theOverlayView = nil;
for (MKPolygon *theOverlay in overlays) {
if (theOverlay == overlay) {
MKPolygonView *thePolygonView = [[[MKPolygonView alloc] initWithPolygon:theOverlay] autorelease];
theOverlayView = thePolygonView;
}
}
return theOverlayView;
}
As far as I can see this should technically work. But it doesn't, the App just crashes when it gets to the region of the map that I think its on (points may be wrong because of lat long mixup or conversion mistake but thats another thing)
Am I missing some property I need to set or could the incorrect points be causing the crash? Or am I missing it entirely?
Cheers for any help.
This was actually correct but I made a mistake putting more than I remembered into overlays - it was actually and array of dictionaries which stored the MKPolygon and a string. Correcting this got it working.
Ok, so I’m having this problem. What I want to do is manually add multiple annotations to a map. When I add just one annotation, it works flawlessly. The pin drops, you can click on it to see its callout, life is good.
The problem comes when I want to add more than one. When I add the second, suddenly the pin’s aren’t coloured correctly (i.e. depending on their magnitude they should be a certain color, but they’re now both the same…), and more importantly when you click on them, to see their callout, the app crashes with exex_bad_access. I really have no idea what’s wrong, maybe I’m adding too many views to the map? But it’s only 9 pins and the pins themselves add just fine.
Here’s my code…
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableArray *stops = [[NSMutableArray alloc] init]; //Get list of all the stops available
Bus *bus1 = [[Bus alloc] init]; // Bus 1 holds the stops
stops = [bus1 returnStops];
for (NSString *stop in stops) //Go through each stop to add annotation to map
{
Bus *bus2 = [bus1 initWithStop:stop]; //Create an instance of bus with a given stop
MapAnnotation *eqAnn = [MapAnnotation annotationWithBus:bus2];
[self.mapView addAnnotation:eqAnn]; //Add the annotation to the map
//[eqAnn release];
//[bus2 release];
}
[self recenterMap];
[stops release];
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView
viewForAnnotation:(id <MKAnnotation>)annotation {
MKAnnotationView *view = nil;
if(annotation != mapView.userLocation) {
MapAnnotation *eqAnn = (MapAnnotation*)annotation;
view = [self.mapView dequeueReusableAnnotationViewWithIdentifier:#"busLoc"];
if(nil == view) {
view = [[[MKPinAnnotationView alloc] initWithAnnotation:eqAnn
reuseIdentifier:#"busLoc"] autorelease];
}
CGFloat magnituide = [eqAnn.bus.magnitude floatValue];
if(magnituide >= .80f) {
[(MKPinAnnotationView *)view setPinColor:MKPinAnnotationColorRed];
} else if(magnituide >= .60f) {
[(MKPinAnnotationView *)view setPinColor:MKPinAnnotationColorPurple];
} else
{
[(MKPinAnnotationView *)view setPinColor:MKPinAnnotationColorGreen];
}
[(MKPinAnnotationView *)view setAnimatesDrop:YES];
[view setCanShowCallout:YES];
}
return view;
}
even tried removing the second function, but it didn’t do anything.
Thanks for the help!
P.S I should also add, there’s usually one or two pins out of the 9 which works when you click the annotation…
If i even try to manually just two annotations by hand in the program (i.e., remove the loop), it still fails and the color is still wrong...
It would appear that your memory management of the stops variable is incorrect. You allocate a mutable array, then replace that array with the return value of -[Bus returnStops], then release that. Also it's not clear what's going on with bus2 - does -[Bus initWithStop:] return a different instance of Bus? It's not usual to send any method -init* on an already-initialised object. I think that you probably are confused by the memory management conventions in Cocoa Touch. Here's a collection of articles and other references on Cocoa memory management (which is the same beast).
Have you tried using AddAnnotations instead of add annotation? - (void)addAnnotations:(NSArray *)annotations. This might work for you...but looking at the answer above and further inspection you are having some memory managment issues in your viewDidLoad (though thi s might not be the cause of your problem, but it could be). First of you are allocating the array (stops) and then ovveriding it with some array in the Bus object, this will cause a leak. Also you are then releasing that array which might be causing the crash since you are releasing the array that is actually in the Bus object w ithout having increased a reference count to it. I am not sure what initWithStop is doing but you might be getting a leak here too if initWithStop retains the object.
I wouldn't call it a memory management problem -- I'd just say you are using array references incorrectly.
After constructing the array with NSMutableArray *stops = [[NSMutableArray alloc] init], the next step is to use [stops addObject: ] to add each stop you want to store.
After that? It's not clear what you are really trying to do.
SO the answer was that I kept sending bus1 the init object, so it got confused.
"Hi David,
Your data model looks hosed to me. You only have one bus object that you are repeatedly sending initWithStop: to.
Hope this helps.
Good luck!
"
Thank you guys for your help! You all helped me quite a bit!