Reputation: 2776
In my app, there is a mapView that the user can add annotations to by pressing the screen. When the annotations are dropped onto the mapView, they are added to a mutable array in a singleton. The annotation views have a callout button that pushes a detailed view (it is called the PinViewController) onto the stack when it is pressed. My problem is that when the callout button is pressed, I want to pass the index of that annotation object to the detail view controller, so that I can get the address and date from that object. But whenever I press the callout button, no matter which annotation it is, it always passed the index of the first object in the array. I do not see what I am doing wrong, can someone help me out? Here is some code:
- (void)mapView:(MKMapView *)mapView
annotationView:(MKAnnotationView *)view
calloutAccessoryControlTapped:(UIControl *)control {
PinViewController *pvc = [[PinViewController alloc]init];
[[self navigationController]pushViewController:pvc animated:YES];
NSUInteger pinIndex = [[Data singleton].annotations indexOfObject:view.annotation];
[pvc setIdentifier:pinIndex];
}
This is from the detail view controller:
- (void)viewDidLoad {
[super viewDidLoad];
[self.labelView setFrame:CGRectMake(10, 260, 300, 230)];
[PinViewController roundView:self.labelView onCorner:UIRectCornerAllCorners radius:15];
[[self view]addSubview:self.labelView];
self.annotation = [[Data singleton].annotations objectAtIndex:self.identifier];
self.addressLabel.text = self.annotation.address;
self.dateLabel.text = self.annotation.subtitle;
}
Here is where the annotations are added to the array:
- (void)press:(UILongPressGestureRecognizer *)recognizer {
CGPoint touchPoint = [recognizer locationInView:self.worldView];
CLLocationCoordinate2D touchMapCoordinate = [self.worldView convertPoint:touchPoint toCoordinateFromView:self.worldView];
self.geocoder = [[CLGeocoder alloc]init];
CLLocation *location = [[CLLocation alloc]initWithCoordinate:touchMapCoordinate
altitude:CLLocationDistanceMax
horizontalAccuracy:kCLLocationAccuracyBest
verticalAccuracy:kCLLocationAccuracyBest
timestamp:[NSDate date]];
[self.geocoder reverseGeocodeLocation:location
completionHandler:^(NSArray *placemarks, NSError *error) {
//NSLog(@"reverseGeocoder:completionHandler: called");
if (error) {
NSLog(@"Geocoder failed with error: %@", error);
} else {
CLPlacemark *place = [placemarks objectAtIndex:0];
self.geocodedAddress = [NSString stringWithFormat:@"%@ %@, %@ %@", [place subThoroughfare], [place thoroughfare], [place locality], [place administrativeArea]];
if (UIGestureRecognizerStateBegan == [recognizer state]) {
self.addressPin = [[MapPoint alloc]initWithAddress:self.geocodedAddress
coordinate:touchMapCoordinate
title:self.geocodedAddress];
[[Data singleton].annotations addObject:self.addressPin];
[self.worldView addAnnotation:self.addressPin];
NSLog(@"The number of pins in the annotation array is: %u",[Data singleton].annotations.count);
}
}
}];
}
So basically, the index passed to the PinViewController is always 0, no matter which annotation it is. I don't understand why this code doesn't work.
Upvotes: 0
Views: 225
Reputation: 41143
NSArray indexOfObject method calls isEqual on each array member to determine if they're the same. Have you made sure your objects only return YES if they're actually equal? I suspect your objects returns YES even if they're inequal
Starting at index 0, each element of the array is sent an isEqual: message until a match is found or the end of the array is reached. This method passes the anObject parameter to each isEqual: message. Objects are considered equal if isEqual: (declared in the NSObject protocol) returns YES.
Common foundation classes like NSNumber already had isEqual
implemented for you, hence you can use it right away in array indexOfObjects
method
NSMutableArray* arr = [[NSMutableArray alloc] init];
[arr addObject:[NSNumber numberWithInt:3]];
[arr addObject:[NSNumber numberWithInt:2]];
[arr indexOfObject:[NSNumber numberWithInt:2]]; // gives 1
However when you implemented a custom class such as MapView
, Objective C wouldn't have any idea how to compare your object, hence you have to implement the isEqual
comparator yourself
Assuming MapView
has an integer property called cow
from which you decide the equality (eg: if two MapView
has the same cow
value, then they are equal), you would write something like this:
@interface MapView : NSObject {
}
@property (nonatomic, assign) int cow;
- (BOOL)isEqual:(id)object
@implementation MapView
@synthesize cow
- (BOOL) isEqual:(id)object
{
MapView* otherMapview = (MapView*) object;
return cow == otherMapview.cow;
}
Upvotes: 3