Chandler De Angelis
Chandler De Angelis

Reputation: 2776

Cannot get object from NSMutableArray

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

Answers (1)

gerrytan
gerrytan

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

https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSArray_Class/NSArray.html

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

Related Questions