With the current approach of adding a formatted string representation (that includes the sequence number) of each annotation to the mapAnnotationArray
, the process of maintaining the array is tedious:
- To update a field inside one of the formatted strings, you have to:
a. Loop through the array,
b. Parse the string (eg. usingcomponentsSeparatedByString
),
c. Check if the field(s) match the annotation you are looking for,
d. Rebuild the formatted string with new values,
e. Update the string in the array usingreplaceObjectAtIndex:withObject:
- To remove an entry from the array, you have to:
a. Do the same steps as 1a to 1c,
b. Remove the string usingremoveObjectAtIndex:
c. Update the annotation sequence number in all the remaining annotations
These steps would have to be done every time you want to retrieve or search for a field in mapAnnotationArray
. It's not efficient or flexible (what if user decides to use a comma in the subtitle, what if address contains a comma, etc).
Instead, store the annotation objects themselves in mapAnnotationArray
and only generate the formatted string representation when you need to submit the data to the server. Storing a proper object in the array lets you take advantage object-oriented methods.
In the method that adds the annotation to the map, instead of adding the formatted string to
mapAnnotationArray
, add the annotation itself:[self.mapAnnotationArray addObject:mapPoint];
Where you update the annotation's
subtitle
in the alert view delegate method, you don't need to do anything tomapAnnotationArray
now because the annotation object in the array is the exact same object you updated thesubtitle
of. You can NSLog the array here to see the change.Where you remove the annotation in the alert view delegate method, you need to remove the same object from
mapAnnotationArray
(the map view doesn't know about your array):if (buttonIndex == 2) { if (self.map.selectedAnnotations.count > 0) { id<MKAnnotation> ann = [self.map.selectedAnnotations objectAtIndex:0]; if ([ann isKindOfClass:[MapAnnotation class]]) { [self.mapAnnotationArray removeObject:ann]; } [self.map removeAnnotations:self.map.selectedAnnotations]; } }
Next, to make it easier to generate the formatted string and to debug the contents of
mapAnnotationArray
, add a helper method and an override for thedescription
method to yourMapAnnotation
class:-(NSString *)stringForServer //You can name this method whatever you want. //Builds the comma-delimited representation //of this annotation (excluding the sequence number). //Note this format still "breaks" if title or subtitle contain commas. { NSString *result = [NSString stringWithFormat:@"%f,%f,%@,%@", self.coordinate.latitude, self.coordinate.longitude, self.title, self.subtitle]; return result; } -(NSString *)description //This method must be named this. //When you NSLog this object, it will call this method to get //what string to display for it. { return [NSString stringWithFormat:@"%@ (%@)", [super description], [self stringForServer]]; }
Finally, wherever you submit the data to the server, loop through the array and generate the formatted strings from the annotation objects (and prefix the sequence number). This example just loops through the array and NSLogs the formatted string for each annotation:
for (int i=0; i < self.mapAnnotationArray.count; i++) { MapAnnotation *ma = (MapAnnotation *)[self.mapAnnotationArray objectAtIndex:i]; NSString *maString = [ma stringForServer]; NSString *fullStringForServer = [NSString stringWithFormat:@"%d,%@", i, maString]; NSLog(@"maa[%d] = %@", i, fullStringForServer); }
Prefixing the sequence number when you are actually ready to save the data avoids re-numbering and duplication problems. Of course, this assumes that annotations don't have to keep the same sequence number across saves.
Also consider using JSON instead of a comma-delimited format.
NSJSONSerialization
makes it relatively easy. See Convert an iOS objective c object to a JSON string for an example.