Reputation: 326
I'm trying to fetch the particular details on which MapAnnotation
the user clicks.the details are fetched from plist
file. for this function i've used - (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view;
on using this.while i click on particular annotation
it fetches location details fromMap
as "Pune, Maharashtra, India @ <+18.50565666,+73.85559082> +/- 0.00m"
and it does not checks my plist values.even after i given these values as attributes in plist as latlong for each location.can anybody solve my problem?
My plist file details:
2013-02-18 12:16:56.039 MapView[9407:13d03] {
contents = "This Fish will be Found Rarely in South Asia";
imagesName = "kfish.jpg";
latlong = "Bangalore, Karnataka, India @ <+12.98333330,+77.58333330> +/- 0.00m";
listName = kFish;
location = "Bangalore, Karnataka, India";
}
2013-02-18 12:16:56.039 MapView[9407:13d03] {
contents = "This Fish will be Found Rarely in South Asia";
imagesName = "wallfish.png";
latlong = "Delhi, India @ <+28.59100531,+77.08826373> +/- 0.00m";
listName = WallFish;
location = "Delhi, India";
}
2013-02-18 12:16:56.039 MapView[9407:13d03] {
contents = "This Fish will be Found Rarely in South Asia";
imagesName = "fish.jpg";
latlong = "Chennai, Tamil Nadu, India @ <+13.07983465,+80.24625757> +/- 0.00m";
listName = Fish;
location = "Chennai,TamilNadu,India";
}
2013-02-18 12:16:56.039 MapView[9407:13d03] {
contents = "This Fish will be Found Rarely in South Asia";
imagesName = "bluefish.jpg";
latlong = "Mumbai, Maharashtra, India @ <+18.99460885,+72.82287598> +/- 0.00m";
listName = BlueFish;
location = "Mumbai, Maharashtra, India";
}
2013-02-18 12:16:56.040 MapView[9407:13d03] {
contents = "This Fish will be Found Rarely in South Asia";
imagesName = "Rarefish.jpg";
latlong = "Chennai, Tamil Nadu, India @ <+13.07983465,+80.24625757> +/- 0.00m";
listName = RareFish;
location = "Chennai,TamilNadu,India";
}
My Coding:
- (void)geocodeRequest
{
CLGeocoder *geocoder = [[CLGeocoder alloc]init];
for (int i = 0; i < total; i++) {
NSString *address = [allValues objectAtIndex:i] ;
[geocoder geocodeAddressString:address completionHandler:^(NSArray *placemarks, NSError *error) {
CLPlacemark *geocodedPlacemark = [placemarks objectAtIndex:0];
MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate:geocodedPlacemark.location.coordinate addressDictionary:geocodedPlacemark.addressDictionary];
int zoomLevel=20;
MKCoordinateRegion region=MKCoordinateRegionMake(geocodedPlacemark.location.coordinate, MKCoordinateSpanMake(zoomLevel,zoomLevel));
[self.mapView addAnnotation:placemark];
[self.mapView setRegion:region animated:YES];
[self.mapView setZoomEnabled:YES];
}];
}
-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view{
total = self.arrayImages.count;
NSArray *newIndex = [mapView selectedAnnotations];
NSLog(@"sel :%@",newIndex);
for (index = 0; index < total; index++) {
dict = [self.arrayImages objectAtIndex:index];
NSLog(@"%@",dict);
if (latlong == newIndex) {
CGRect rec = CGRectMake(0, 0, 250, 250);
[self setView:[[[UIView alloc] initWithFrame:rec] autorelease]];
[[self view] setBackgroundColor:[UIColor whiteColor]];
UIImage *img = [UIImage imageNamed:[dict objectForKey:@"imagesName"]];
UIImageView *im = [[UIImageView alloc] initWithImage:img];
UILabel *lab1 = [[UILabel alloc] init];
UITextView *detailsView = [[UITextView alloc] init];
lab1.text = [NSString stringWithFormat:[dict objectForKey:@"listName"]];
detailsView.text = [NSString stringWithFormat:[dict objectForKey:@"contents"]];
detailsView.editable = NO;
detailsView.bounds = CGRectMake(20, 20, 150, 150);
detailsView.frame = CGRectMake(210, 720, 390, 350);
detailsView.font = [UIFont systemFontOfSize:24];
lab1.bounds = CGRectMake(20, 20, 150, 150);
lab1.frame = CGRectMake(360, 600, 90, 50);
lab1.font = [UIFont systemFontOfSize:24];
im.bounds = CGRectMake(10, 10, 50, 50);
im.frame = CGRectMake(200, 120, 370, 450);
[UIView transitionWithView:[self view] duration:1.5
options:UIViewAnimationOptionTransitionCurlUp
animations:^ { [[self view] addSubview:im];
[[self view] addSubview:lab1];
[[self view] addSubview:detailsView];
}completion:nil];
}
}
}
MapView Works fine.but on fetching the selected location only it's not working.can anybody help me where have i went wrong??
Thanks In Advance.
Upvotes: 2
Views: 420
Reputation: 437882
In your didSelectAnnotationView
method, you appear to be iterating through your arrayImages
, looking for one whose latlong == newIndex
. A couple of thoughts:
Using the equality operator, ==
for comparing objects, is generally not a prudent technique. You have no assurances that the map view's annotation is the same object (if their properties were using copy
, it would not be equal, because the address for your object and theirs may be different). And even if it did happen to work, it's not very reliable way to work.
I'm not quite if I follow your logic, anyway, even if the equality operator did work, because in geocodeRequest
you are making a new MKPlacemark
, from allValues
, but in didSelectAnnotationView
you're comparing it to the arrayImages
. And your if
statement in didSelectAnnotationView
is looking at latlong
and newIndex
(the former I don't see you setting, the latter is an array of annotations). It just doesn't make sense to me. I don't see how they could possibly match.
But those two prior points are irrelevant, because the proper solution is to not add your MKPlacemark
to your map and then iterate through your list in didSelectAnnotationView
hunting for a match, but instead, to create your own annotation class with all of the properties you want to be able to retrieve when a user taps on the annotation view. Or, at the very least, have your own annotation subclass and define a property that you can use to look up the particular details from your array. Either approach works. But the key is to not try to iterate through your objects looking for a match, but rather define a custom annotation that has everything you need to find it right away.
For examples of custom annotations, see the Defining a Custom Annotation Object section of the Location Awareness Programming Guide. Once you've defined your own annotation subclass with all of the extra properties that you think you'll need, you would then (a) change your geocodeRequest
to create instances of your new annotation subclass rather than MKPlacemark
; and (b) change your didSelectAnnotationView
to just grab the necessary data from the annotation
(which is a property of the annotationView
). That way, it completely eliminates the headache of iterating through your list of possible annotations looking for a match.
FYI, in another S.O. answer, I give some examples on options on handling callouts, popovers, etc., so maybe there is something there that might be helpful background for you, too. I don't use custom annotations there, but maybe it gives you some ideas about your integration with MapKit.
Let me illustrate this practice. Let's say that we want to annotate our map, but want to keep track of additional properties. First, I'll define an annotation custom class that has my additional properties. (I'll subclass this from MKPointAnnotation
to make life a little easier for me.)
@interface CustomAnnotation : MKPointAnnotation
@property (nonatomic) NSUInteger index;
@property (strong, nonatomic) NSString *property1;
@property (strong, nonatomic) NSString *property2;
@property (strong, nonatomic) NSString *property3;
@end
Now, when I want to add my annotations to my map view, I'll use my custom annotation class, making sure to set whatever properties I want. You could save the numeric index in your array, or save the actual properties you care about, or both:
CustomAnnotation *annotation = [[CustomAnnotation alloc] init];
// set the MKPointAnnotation standard properties
annotation.title = item.name;
annotation.coordinate = item.placemark.coordinate;
// set my custom properties
annotation.index = idx;
annotation.property1 = ...;
annotation.property2 = ...;
annotation.property3 = ...;
// now add the annotation to the map view
[annotations addObject:annotation];
Or, if you wanted to take advantage of all of the properties of a MKPlacemark
, you could do the following:
@interface CustomAnnotation : MKPlacemark
@property (strong, nonatomic) NSString *title; // MKPlacemark doesn't have title, so let's add our own property for that
@property (nonatomic) NSUInteger index;
@property (strong, nonatomic) NSString *property1;
@property (strong, nonatomic) NSString *property2;
@property (strong, nonatomic) NSString *property3;
@end
And you'd create the annotation like you'd create an MKPlacemark
, but again, set our custom properties:
CustomAnnotation *annotation = [[CustomAnnotation alloc] initWithPlacemark:item.placemark];
// set my custom properties
annotation.title = item.name;
annotation.index = idx;
annotation.property1 = ...;
[annotations addObject:annotation];
Now, when I select the annotation view, I can handle accordingly:
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
if ([view.annotation isKindOfClass:[CustomAnnotation class]])
{
CustomAnnotation *annotation = view.annotation;
// note, I don't have to iterate through any arrays to figure out which
// annotation I'm dealing with; I can just look at my custom properties
NSLog(@"index = %d; property1 = %@", annotation.index, annotation.property1);
// now do whatever you want with that annotation; I could look up the
// annotations's details by using the custom `index` property I defined,
// or if I defined my annotations to store all of the detail properties
// I needed, I can just access them directly
}
}
As an aside, rather than using didSelectAnnotationView
, you might want to adopt a more standard MKMapView
behavior, and show the standard callout bubble, set the right callout bubble accessory, and then handle clicking on that callout accessory:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if (![annotation isKindOfClass:[CustomAnnotation class]])
return nil;
MKAnnotationView *annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:@"CustomAnnotationView"];
annotationView.canShowCallout = YES;
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
return annotationView;
}
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
if (![view.annotation isKindOfClass:[CustomAnnotation class]])
return;
CustomAnnotation *annotation = view.annotation;
// note, I don't have to iterate through any arrays to figure out which
// annotation I'm dealing with; I can just look at my custom properties
NSLog(@"index = %d; property1 = %@", annotation.index, annotation.property1);
// now do whatever you want with that annotation; I could look up the
// annotations's details by using the custom `index` property I defined,
// or if I defined my annotations to store all of the detail properties
// I needed, I can just access them directly
}
Upvotes: 1