Adding Multiple Annotations to Map But All Show Some of Same Data
Asked Answered
D

2

8

UPDATE 2:

Here is the existing code within maps, but it is like the annotations get all out of order with the pins. One time a pin will be green, the next time I run it, the same pin is red. Where is the disconnect coming from?

-(void) viewWillAppear:(BOOL)animated {
    self.annotationArray = [[NSMutableArray alloc] init];

CLLocationCoordinate2D coord = {.latitude =  15.8700320, .longitude =  100.9925410};
MKCoordinateSpan span = {.latitudeDelta =  3, .longitudeDelta =  3};
MKCoordinateRegion region = {coord, span};
[mapViewUI setRegion:region];
    PFQuery *query = [PFQuery queryWithClassName:@"Share"];
    [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
        if (!error) {
                       self.mapViewData = objects;
                        for (int i=0;i<[objects count];i++)
            {
                // Question * q = [[Question alloc]init];

                PFObject * obj = [self.mapViewData objectAtIndex:i];
                NSLog(@"%@", obj);
                self.theObject = obj;

                NSString *string = obj[@"WhereAt"];


                NSArray *stringArray = [string componentsSeparatedByString: @","];

                CLLocationDegrees myLatitude = [[stringArray objectAtIndex:0] doubleValue];
                CLLocationDegrees myLongitude = [[stringArray objectAtIndex:1] doubleValue];
                CLLocationCoordinate2D coord2 = {.latitude =  myLatitude, .longitude =  myLongitude};
                NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
                dateFormatter.dateFormat = @"MMM dd, yyyy";

                MKPointAnnotation *annotation2 = [[MKPointAnnotation alloc] init];
                [annotation2 setCoordinate:coord2];
                [annotation2 setTitle:obj[@"FamilyName"]];
                [annotation2 setSubtitle:obj[@"Result"]];
                [mapViewUI addAnnotation:annotation2];


            }


        } else {
            // Log details of the failure
            NSLog(@"Error: %@ %@", error, [error userInfo]);
        }


    }];

}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
    if (annotation == mapViewUI.userLocation)
    {
        return nil;
    }
    else
    {
    NSUInteger index = [[mapView annotations] indexOfObject:annotation];
    PFObject *objectForCurrentAnnotation = [self.mapViewData objectAtIndex:index];
    MKPinAnnotationView *annotationView = [[MKPinAnnotationView alloc] init];

    annotationView.enabled = YES;
    annotationView.canShowCallout = YES;
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    dateFormatter.dateFormat = @"MMM dd, yyyy";
    NSString *theResult = objectForCurrentAnnotation[@"Result"];
    NSLog(@"Result is %@", theResult);

    if ([theResult isEqualToString:@"Accepted Bible"]) {
        NSLog(@"Accepted");
        annotationView.pinTintColor = [UIColor greenColor];

    }
   else if ([theResult isEqualToString:@"Requested Different Material"]) {
       NSLog(@"Different");

        annotationView.pinTintColor = [UIColor blackColor];

    }
   else if ([theResult isEqualToString:@"Not Home"]) {
      NSLog(@"Not Home");

        annotationView.pinTintColor = [UIColor yellowColor];

    }
   else if ([theResult isEqualToString:@"Rejected Bible"]) {
       NSLog(@"Rejected");

        annotationView.pinTintColor = [UIColor redColor];

    }



    return annotationView;
    }

    return nil;
}

UPDATE:

I see now that the issue is that self.theObject is set one time, so it just pulls data from that for everything not handled by Annotations. I guess the issue now is, how can I get it to show for each object instead of whatever the last one set was?

My app uses Parse.com and PFObjects. The app queries the PFObject to get all the data for each entry in the row, pulls out the coordinates for a given location for that entry, along with various bits of data, and adds an annotation for each of those. When I set the MKAnnotationView for this so that I can have multiple colored pins outside of what Apple generally lets you easily do, I run into issues. The image and some of the data for the annotation sets each pin to whatever the last one called was. The title and subtitle are fine, but not the color or callout image. Here is my code, what is going on wrong here?

-(void) viewWillAppear:(BOOL)animated {
CLLocationCoordinate2D coord = {.latitude =  15.8700320, .longitude =  100.9925410};
MKCoordinateSpan span = {.latitudeDelta =  3, .longitudeDelta =  3};
MKCoordinateRegion region = {coord, span};
[mapView setRegion:region];
    PFQuery *query = [PFQuery queryWithClassName:@"Share"];
    [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
        if (!error) {
            NSLog(@"YAY");
            // The find succeeded. The first 100 objects are available in objects
            //  questionsList = [[NSMutableArray alloc]init];
            NSLog(@"Objects%lu", (unsigned long)[objects count]);

            for (int i=0;i<[objects count];i++)
            {
                // Question * q = [[Question alloc]init];

                PFObject * obj = [objects objectAtIndex:i];
                self.theObject = obj;

                NSString *string = obj[@"WhereAt"];


                NSArray *stringArray = [string componentsSeparatedByString: @","];

                CLLocationDegrees myLatitude = [[stringArray objectAtIndex:0] doubleValue];
                CLLocationDegrees myLongitude = [[stringArray objectAtIndex:1] doubleValue];
                CLLocationCoordinate2D coord2 = {.latitude =  myLatitude, .longitude =  myLongitude};
                NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
                dateFormatter.dateFormat = @"MMM dd, yyyy";
                NSString *theResult = obj[@"Result"];


                NSString *theDate = [dateFormatter stringFromDate:obj[@"DateVisited"]];
                NSString *combined = [[theResult stringByAppendingString:@" on "] stringByAppendingString:theDate];
                NSString *theTitle = [[obj[@"FamilyName"] stringByAppendingString:@" "] stringByAppendingString:obj[@"StreetAddress"]];

                MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
                [annotation setCoordinate:coord2];
                [annotation setTitle:theTitle];
                [annotation setSubtitle:combined];

                [mapView addAnnotation:annotation];

            }


        } else {
            // Log details of the failure
            NSLog(@"Error: %@ %@", error, [error userInfo]);
        }
    }];



}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {


    MKPinAnnotationView *annotationView = [[MKPinAnnotationView alloc] init];

    annotationView.enabled = YES;
    annotationView.canShowCallout = YES;
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    dateFormatter.dateFormat = @"MMM dd, yyyy";
    NSString *theResult = self.theObject[@"Result"];
    NSLog(@"Result is %@", theResult);

    if ([theResult isEqualToString:@"Accepted Bible"]) {
      //  NSLog(@"Accepted");
        annotationView.pinTintColor = [UIColor greenColor];

    }
   else if ([theResult isEqualToString:@"Requested Different Material"]) {
       //NSLog(@"Different");

        annotationView.pinTintColor = [UIColor blackColor];

    }
   else if ([theResult isEqualToString:@"Not Home"]) {
      // NSLog(@"Not Home");

        annotationView.pinTintColor = [UIColor yellowColor];

    }
   else if ([theResult isEqualToString:@"Rejected Bible"]) {
       //NSLog(@"Rejected");

        annotationView.pinTintColor = [UIColor redColor];

    }
    //annotationView.image = [UIImage imageNamed:@"arrest.png"];//here we use a nice image instead of the default pins
    PFFile *thumbnail = self.theObject[@"HousePicture"];
    [thumbnail getDataInBackgroundWithBlock:^(NSData *imageData, NSError *error) {

        UIImage *thumbnailImage = [UIImage imageWithData:imageData];
        self.theImage = thumbnailImage;
        //annotationView.image = thumbnailImage;
        UIView *leftCAV = [[UIView alloc] initWithFrame:CGRectMake(0,0,60,60)];
        UIImageView *theImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 60, 60)];
        theImageView.image = self.theImage;
        annotationView.leftCalloutAccessoryView = leftCAV;
        [leftCAV addSubview:theImageView];
        annotationView.canShowCallout = YES;

    }];


    return annotationView;


    return nil;
}
Donavon answered 30/8, 2016 at 19:20 Comment(0)
S
0

Subclass MKPointAnnotation for example MyPointAnnotation add a property result

@interface MyPointAnnotation : MKPointAnnotation
    @property (nonatomic, strong) NSString *result;
@end

In viewWillAppear: modify these lines

NSString *theResult = obj[@"Result"];

MyPointAnnotation *myAnnotation = [[MyPointAnnotation alloc] init];
[myAnnotation setCoordinate:coord2];
[myAnnotation setTitle:theTitle];
[myAnnotation setSubtitle:combined];
[myAnnotation setResult:theResult];

[mapView addAnnotation:myAnnotation];

In viewForAnnotation: delegate method get the result like this

MyPointAnnotation *myAnnotation = (MyPointAnnotation *)annotation;
NSString *theResult = myAnnotation.result;
Sling answered 4/9, 2016 at 8:0 Comment(0)
A
0

You can solve this in a few different ways.

1. MKMapView class has property called annotations. By calling this property it will return you sorted array of all annotations on your map which is co-related with order of your data in your initial array. In this way you just have to store all fetched objects from Parse. In the interface in your view controller just add a new property:

@property (nonatomic, string) NSArray *mapViewData;

In your viewWillAppear method:

    [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
            if (!error) {
                self.mapViewData = objects;
               // here you form your annotations
            }
    }];

Then just pull this data in delegate method

 - (nullable MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
     NSUInteger index = [[mapView annotations] indexOfObject:annotation];
     PFObject *objectForCurrentAnnotation = [self.mapViewData objectAtIndex:index];
     // do your customisation
}

2. Override and subclass the MKPointAnnotation object.

@interface SuperAnnotation : MKPointAnnotation

@property (nonatomic, strong) PFObject *dataObject;

@end

@implementation SuperAnnotation

- (void)setDataObject:(PFObject *)dataObject {
    _dataObject = dataObject;

    self.title = // calculate your string for title
    self.subtitle = // and the same for subtitle
}

@end

And then in delegate method just get this object from annotation object and do what you want

- (nullable MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
     PFObject *objectForCurrentAnnotation = ((SuperAnnotation *) annotation).dataObject;    
     // do your customisation
}

3. You can create dictionary which will store pairs of MKAnnotation and PFObject that you need for customisation (not recommended for big amount of data).

@property (nonatomic, string) NSMutableDictionary *dataDictionary;

in viewWillAppear:

[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
        if (!error) {
            self.dataDictionary = [NSMutableDictionary new];
           // here you form your annotations

            [self.dataDictionary setObject:yourPFObject forKey:yourAnnoationObject];
        }
}];

And then yet again pull the data in delegate:

 - (nullable MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
     PFObject *objectForCurrentAnnotation = [self.dataDictionary objectForKey:annotation];
     // do your customisation
}
Anabasis answered 7/9, 2016 at 10:19 Comment(5)
I have been out of town and just got back to try out Option #1 you wrote. However, I am still having somewhat of some difficulties. It is now showing different colors, but it doesn't always match up with the correct locations. For example, I tell it to do green if result is Accepted Bible. The map annotation will correctly say on subtitle that it was Accepted Bible, but color will show rejected.Donavon
@Donavon try method number 2.Anabasis
@Donavon what do you mean color rejected?Anabasis
In the self.mapViewData which is just the PFObject, one field is called Result. That result contains, Accepted Bible, Rejected Bible, Not Home, Requested Different Material, and each should show a different color pin based on that result. However, it is like the annotations are getting mixed up with each other, and I run the app one time and one entry shows one color, but I run it the next time and it uses a different color, and I don't know why. Will update OP with existing code.Donavon
Seems like your MKMapView doesn't keep order of MKAnnotations. Try one of two other approaches. Should help. Because, only first solution rely on order of MKAnnotations array.Anabasis

© 2022 - 2024 — McMap. All rights reserved.