Zoom to random annotation and show bubble when map view loads - ios

I am trying to zoom to a random annotation AND have the bubble open automatically as well.
I am pinning my annotations in the viewDidLoad as follows:
...arrays...
for (int i=0; i<22; i++){
MKPointAnnotation *annot = [[MKPointAnnotation alloc] init];
annot.title = [wineryName objectAtIndex:i];
annot.subtitle = [wineryAddress objectAtIndex:i];
annot.coordinate = CLLocationCoordinate2DMake([[lat objectAtIndex:i]doubleValue], [[lon objectAtIndex:i]doubleValue]);
[mapView setCenterCoordinate:annot.coordinate animated:YES];
[mapView addAnnotation:annot];
then I am styling the bubble as follows:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
//dequeue an existing pin view first
static NSString* AnnotationIdentifier = #"AnnotationIdentifier";
MKPinAnnotationView* pinView = [[[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier] autorelease];
pinView.animatesDrop=YES;
pinView.canShowCallout=YES;
pinView.pinColor=MKPinAnnotationColorRed;
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(0, 0, 35, 35);
button.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
[button setImage:[UIImage imageNamed:#"RightArrow.png"] forState:UIControlStateNormal];
[button addTarget:self action:#selector(showDetails:) forControlEvents:UIControlEventTouchUpInside];
pinView.rightCalloutAccessoryView = button;
...arrays...
for (int i = 0; i < 22; i++) {
if ([wineryTitle[i] isEqualToString:[annotation title]]) {
UIImageView *profileIconView = [[UIImageView alloc] init];
profileIconView.frame = CGRectMake(0, 0, 40, 33);
profileIconView.image = [UIImage imageNamed:wineryImage[i]];
pinView.leftCalloutAccessoryView = profileIconView;
[profileIconView release];
break;
}
}
return pinView;
}
then I am trying to zoom to a random location as follows:
- (void)zoomToUserLocation:(MKUserLocation *)userLocation
{
if (!userLocation)
return;
MKCoordinateRegion region;
//zoom to random pin when page loads
int randomNumber = rand() % 22;
switch (randomNumber) {
case 1:
region.center = CLLocationCoordinate2DMake(34.642109, -120.440292);
[self.mapView selectAnnotation:[self.mapView.annotations objectAtIndex:0] animated:TRUE];
break;
case 2:
region.center = CLLocationCoordinate2DMake(34.667408, -120.334781);
[self.mapView selectAnnotation:[self.mapView.annotations objectAtIndex:1] animated:TRUE];
break;
case 3:
...etc
}
region.span = MKCoordinateSpanMake(5.0, 5.0);
region = [self.mapView regionThatFits:region];
[self.mapView setRegion:region animated:YES];
}
ALL OF THIS WORKS< EXCEPT: In the zoomToUserLocation method, the map is zooming to one location and then showing the bubble of a different location. It seems like the random operator is randomly selecting a location and a bubble separately. Does anyone know how to fix this so that the bubble automatically appears at the same location that is randomly selected?

The code in the zoomToUserLocation method is making the wrong assumption that the map view's annotations array only contains the annotations you explicitly added and (more importantly) that the annotations array will be in the same order that you added the annotations in.
Both of those assumptions are unsafe to make.
For some more discussion, see MKMapView annotations changing/losing order?.
Your app is apparently adding 22 annotations but:
If showsUserLocation is YES, then the map view's annotations array will contain 23 annotations (your 22 and the user location that the map adds itself).
There is no guarantee that the annotation at index N of the map's annotations array will be the same annotation that is at index N in your winery array.
For your purpose of simply zooming to a random location, it is not really necessary to establish a link between the map's annotations array and your own array(s).
Instead, the coordinates to center on can be retrieved from the randomly chosen annotation from the annotations array itself.
For example:
MKCoordinateRegion region;
//make list of annotations excluding the user location
NSMutableArray *myAnnotations = [NSMutableArray arrayWithCapacity:10];
for (id<MKAnnotation> ann in self.mapView.annotations)
{
if (! ([ann isKindOfClass:[MKUserLocation class]]))
[myAnnotations addObject:ann];
}
int numOfAnnotations = myAnnotations.count;
//if no annotations to choose from, do nothing
if (numOfAnnotations == 0)
return;
int randomNumber = rand() % numOfAnnotations;
//suggest using arc4random instead of rand
//see https://stackoverflow.com/questions/160890/generating-random-numbers-in-objective-c
id<MKAnnotation> randomAnnotation = [myAnnotations objectAtIndex:randomNumber];
region.center = randomAnnotation.coordinate;
[self.mapView selectAnnotation:randomAnnotation animated:YES];
region.span = ... //rest of the code as-is
//however, calling regionThatFits is unnecessary
There are numerous other unrelated improvements that could be made to the code but those will have to be the topic of separate questions. Here are a couple of them however...
One major improvement I can suggest is to create a custom annotation class (called Winery perhaps) which consolidates all the data of a winery into a single object rather than using separate arrays for the name, address, latitude, longitude, image, etc.
This will make development and future changes much easier to manage.
The second major improvement is to remove the inefficient loop in the viewForAnnotation delegate method which searches for the winery name in order to set the left accessory view's image. This search loop is executed every time the annotation view is needed. With just 22 annotations, you may not notice a performance issue but it's unnecessary work. If the first improvement is done, the search loop can be eliminated since all the annotation's properties will already be in the annotation object.
See Optimizing Code for MKMapView - Large Number of Annotations for some idea of the above.

Related

How to add clicked annotations on mapbox using offline mbtiles files

I have already managed to use interactive offline mbtiles (created on TileMill) in order to:
Load more than 1000 points fast
Make them understand when user is clicking each point and show a popup with the name of each point
But I can't make the bubble with the name clickable again.
I use the following code to generate the layer for the annotation of each point
- (RMMapLayer *)mapView:(RMMapView *)mapView layerForAnnotation:(RMAnnotation *)annotation{
RMMarker *marker = [[RMMarker alloc] initWithMapboxMarkerImage:#"embassy"];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 50, 32)];
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.image = annotation.userInfo;
marker.leftCalloutAccessoryView = imageView;
marker.canShowCallout = YES;
return marker;
}
and this is how I get the teaser and build my annotation from the mbtiles file:
- (void)singleTapOnMap:(RMMapView *)mapView at:(CGPoint)point{
[mapView removeAllAnnotations];
RMMBTilesSource *source = (RMMBTilesSource *)mapView.tileSource;
if ([source conformsToProtocol:#protocol(RMInteractiveSource)] && [source supportsInteractivity])
{
NSString *formattedOutput = [source formattedOutputOfType:RMInteractiveSourceOutputTypeTeaser
forPoint:point
inMapView:mapView];
if (formattedOutput && [formattedOutput length])
{
// parse the country name out of the content
//
NSUInteger startOfCountryName = [formattedOutput rangeOfString:#"<strong>"].location + [#"<strong>" length];
NSUInteger endOfCountryName = [formattedOutput rangeOfString:#"</strong>"].location;
NSString *countryName = [formattedOutput substringWithRange:NSMakeRange(startOfCountryName, endOfCountryName - startOfCountryName)];
// parse the flag image out of the content
//
NSUInteger startOfFlagImage = [formattedOutput rangeOfString:#"base64,"].location + [#"base64," length];
NSUInteger endOfFlagImage = [formattedOutput rangeOfString:#"\" style"].location;
UIImage *flagImage = [UIImage imageWithData:[NSData dataFromBase64String:[formattedOutput substringWithRange:NSMakeRange(startOfFlagImage, endOfFlagImage)]]];
RMAnnotation *annotation = [RMAnnotation annotationWithMapView:mapView coordinate:[mapView pixelToCoordinate:point] andTitle:countryName];
annotation.userInfo = flagImage;
[mapView addAnnotation:annotation];
[mapView selectAnnotation:annotation animated:YES];
}
}
}
UPDATED
I figured out how to do that by using a leftCalloutAccessoryView on the marker (I added the following at the end of layerForAnnotation method :
marker.leftCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
and used the following delegate method to track the event:
-(void)tapOnCalloutAccessoryControl:(UIControl *)control forAnnotation:(RMAnnotation *)annotation onMap:(RMMapView *)map{
NSLog(#"I will now pass to the next screen ! YEAH! %#",annotation.title);
}
The problem now is that I want to get rid off the left calloutAccesoryView. Any suggestions?
None of what you have here about the map is needed. What you really want is the callout (which is of type SMCalloutView, a dependent project to the Mapbox SDK that you are using) to have its clicks registered.
Check out this issue for more details:
https://github.com/mapbox/mapbox-ios-sdk/issues/422

SKMaps iOS: Pin disappears when panning the Map

With the new Version (2.1.0) I get a problem. The Annotation disappears when scrolling the map.
In the demo project it works fine. Also adding the frameworks again doesn't help.
- (void)viewDidLoad {
[super viewDidLoad];
placeDetail = [[PlaceDetailViewController alloc] init];
latitude = [placeDetail Latitude];
longitude = [placeDetail Longitude];
self.placeMapView = [[SKMapView alloc] init];
self.placeMapView.frame = CGRectMake(0.0f, 0.0f, CGRectGetWidth(self.view.frame), CGRectGetHeight(self.view.frame));
self.placeMapView.delegate = self;
self.placeMapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.placeMapView.settings.poiDisplayingOption = SKPOIDisplayingOptionNone;
[self.view addSubview:self.placeMapView];
//add a circle overlay
for(int i=0;i<latitude.count;i++)
{
//set the map region
SKCoordinateRegion region;
region.center = CLLocationCoordinate2DMake([latitude[i] floatValue], [longitude[i] floatValue]);
region.zoomLevel = 17;
self.placeMapView.visibleRegion = region;
SKAnnotation *mapAnnotation = [SKAnnotation annotation];
mapAnnotation.identifier = i;
mapAnnotation.minZoomLevel = 5;
mapAnnotation.annotationType = SKAnnotationTypeRed;
mapAnnotation.location = CLLocationCoordinate2DMake([latitude[i] floatValue], [longitude[i] floatValue]);
[self.placeMapView addAnnotation:mapAnnotation];
}
}
Annoation creation
-(void)mapView:(SKMapView *)mapView didSelectAnnotation:(SKAnnotation *)annotation {
self.placeMapView.calloutView.titleLabel.text= placeDetail.Name;
self.placeMapView.calloutView.titleLabel.font = [UIFont fontWithName:#"PTSans-Narrow" size:15];
self.placeMapView.calloutView.subtitleLabel.text = #"";
[self.placeMapView showCalloutForAnnotation:annotation withOffset:CGPointMake(0, 42) animated:YES];
[self.placeMapView.calloutView.rightButton addTarget:self action:#selector(backToDetailView) forControlEvents:UIControlEventTouchUpInside];
}
I would appreciate your help.
EDIT: I think I found the problem that causes this beahvior. In my app I have two kind of maps. One Mini Map and one large Map. But in two different views.
When I deactivate the Mini Map it works. SO I think it has to do with the loading of the SKMap framework. Currently the mini map function is called in view did load method.
So you know what to do here?
It is a bug in the 2.1 and 2.2 versions of the SDK - it will be fixed in 2.3 (eta November 2014).
For 2.1/2.2 there is a workaround: having different id's for the annotations on the minimap and the big map. For example you have N annotations on the minimap with ids 0..N-1, then the big map would have annotations with ids from N onward. So for M annotations on the big map you would have annotations with ids from N..M-1.

MKPinAnnotationView color is not working

I am trying to show some pins from an array, it shows them all but they are red, and not green as i ask them to be.
Why is that ?
//run on array to get all locations
for(int k=0;k<[array count];k=k+2)
{
float targetlat=[[array objectAtIndex:k] floatValue];
float targetlongi=[[array objectAtIndex:k+1] floatValue];
CLLocationCoordinate2D location = CLLocationCoordinate2DMake(targetlat,targetlongi);
NSString *partyTitle = #"title";
MKPinAnnotationView *partyPin = [self returnPointView:location andTitle:partyTitle andColor:MKPinAnnotationColorGreen];
[self.mapView addAnnotation:partyPin.annotation];
}
//function callback is working but its red, and it takes so much time to load
-(MKPinAnnotationView*) returnPointView: (CLLocationCoordinate2D) location andTitle: (NSString*) title andColor: (int) color
{
MKCoordinateRegion region = self.mapView.region;
region.center = location;
region.span.longitudeDelta /= 5.0;
region.span.latitudeDelta /= 5.0;
[self.mapView setRegion:region];
MKPointAnnotation *resultPin = [[MKPointAnnotation alloc] init];
MKPinAnnotationView *result = [[MKPinAnnotationView alloc] initWithAnnotation:resultPin reuseIdentifier:Nil];
[resultPin setCoordinate:location];
resultPin.title = title;
result.pinColor = color;
return result;
}
Regarding the main issue that the pins are red instead of green:
The code creates an MKPinAnnotationView but this view is never given to the map view.
To make the map view use annotation views that you create, you must implement the viewForAnnotation delegate method and return them from there.
Otherwise, the map view has no knowledge of annotation views that you create.
If you don't implement viewForAnnotation, the map view creates a default red pin view.
Regarding the second issue that "it takes so much time to load":
The most likely reason for this is that you are calling setRegion each time you add an annotation.
If you are adding, say, 500 annotations, the map view is setting the region 500 times.
Please note that it is not necessary to call setRegion simply to add an annotation (regardless of the currently-visible region). The annotation's coordinate does not have to be "visible" to add an annotation there.
What you want to do inside the for loop is simply construct a region that includes all the annotations and then call setRegion (or setVisibleRect) once and after all the annotations are added (after the for loop). Constructing an MKMapRect and calling setVisibleMapRect is easier than constructing an MKCoordinateRegion in order to call setRegion.
In iOS 7, this is even simpler: Just call showAnnotations (no manual construction necessary).
Example:
//Initialize the MKMapRect (region) we want to show to null...
MKMapRect showMapRect = MKMapRectNull;
for(int k=0;k<[array count];k=k+2)
{
float targetlat=[[array objectAtIndex:k] floatValue];
float targetlongi=[[array objectAtIndex:k+1] floatValue];
CLLocationCoordinate2D location = CLLocationCoordinate2DMake(targetlat,targetlongi);
NSString *partyTitle = #"title";
//Here, don't create the annotation view.
//Just create the annotation...
MKPointAnnotation *resultPin = [[MKPointAnnotation alloc] init];
[resultPin setCoordinate:location];
resultPin.title = partyTitle;
[self.mapView addAnnotation:resultPin];
//Add this annotation's coordinate
//to the MKMapRect we want to show...
MKMapPoint annMapPoint = MKMapPointForCoordinate(location);
MKMapRect annMapRect = MKMapRectMake(annMapPoint.x, annMapPoint.y, 0, 0);
showMapRect = MKMapRectUnion(showMapRect, annMapRect);
}
mapView.visibleMapRect = showMapRect;
//In iOS 7, instead of constructing MKMapRect manually,
//we could just call showAnnotations...
//[mapView showAnnotations:mapView.annotations animated:YES];
//Implement the viewForAnnotation delegate method...
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
//if annotation is the user location,
//return nil so map view shows default view for it (blue dot)...
if ([annotation isKindOfClass:[MKUserLocation class]])
{
return nil;
}
static NSString *reuseId = #"pin";
MKPinAnnotationView *pav = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:reuseId];
if (pav == nil)
{
pav = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:reuseId];
pav.canShowCallout = YES;
pav.animatesDrop = YES;
pav.pinColor = MKPinAnnotationColorGreen;
}
else
{
pav.annotation = annotation;
}
return pav;
}

mapview random annotation image

I'm having great trouble figuring out what I'm doing wrong here...
I am adding annotations to my mapview through loops, but the annotation image is completely random every time... when I NSLog the order, it's random - i'm not sure if that is the problem.
- (MKAnnotationView *)mapView:(MKMapView *)mapView1 viewForAnnotation:(id<MKAnnotation>)annotation {
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
if ([[annotation subtitle] isEqual:#"Bar"]) {
MKAnnotationView *view = nil;
view = [self.mapView dequeueReusableAnnotationViewWithIdentifier:#"myAnnotationIdentifier"];
if (!view) {
// Could not reuse a view ...
// Creating a new annotation view
view = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"myAnnotationIdentifier"];
view.enabled = YES;
view.canShowCallout = YES;
view.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
view.image = [UIImage imageNamed:#"beer.png"];
}
return view;
}
else if ([[annotation subtitle] isEqual:#"Club"]) {
MKAnnotationView *view = nil;
view = [self.mapView dequeueReusableAnnotationViewWithIdentifier:#"myAnnotationIdentifier"];
if (!view) {
// Could not reuse a view ...
// Creating a new annotation view
view = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"myAnnotationIdentifier"];
view.enabled = YES;
view.canShowCallout = YES;
view.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
view.image = [UIImage imageNamed:#"clubs.png"];
}
return view;
}
}
the view.image is totally random... either clubs.png or beer.png..
How do I make it correctly?
this is how I add the annotations:
- (void)barLoop {
for (int i = 0; i<barArray.count; i++) {
int index = [[barArray objectAtIndex:i]intValue];
NSString *lati = [[[self.usersLocationArray objectAtIndex:index]
valueForKeyPath:#"items.Latitude"]componentsJoinedByString:#""];
NSString *longi = [[[self.usersLocationArray objectAtIndex:index]
valueForKeyPath:#"items.Longitude"]componentsJoinedByString:#""];
NSString *barNavn = [[[self.usersLocationArray objectAtIndex:index] valueForKeyPath:#"items.Navn"]componentsJoinedByString:#""];
float latitude = [lati floatValue];
float longitude = [longi floatValue];
MKCoordinateRegion region = { {0.0, 0.0} , {0.0, 0.0} };
region.center.latitude = latitude;
region.center.longitude = longitude;
region.span.longitudeDelta = 0.20f;
region.span.latitudeDelta = 0.20f;
[mapView setRegion:region animated:NO];
CLLocationCoordinate2D location;
location.latitude = latitude;
location.longitude = longitude;
Annotation *ann = [[Annotation alloc]initWithPosition:location];
ann.title = barNavn;
ann.subtitle = #"Bar";
[self.mapView addAnnotation:ann];
}
}
thanks in advance :)
You have two types of annotations, but you are only setting the image when the annotation is originally created. Thus, if an annotation for a bar scrolls off the map view and another annotation for a club scrolls on, it might reuse the bar's annotation view for the club.
There are two ways of fixing this:
Use different reuseIdentifier parameters for each of the two types of annotation views; or
Set/reset the annotation view's image regardless of whether your call to dequeueReusableAnnotationViewWithIdentifier succeeded in returning a value or not.
Unrelated, but your viewForAnnotation method should:
You might want to use isEqualToString instead of isEqual when checking for #"Bar" vs #"Club".
Make sure to return nil if neither of those if clauses return true (this should never happen, but nonetheless you have a potential path in this routine in which you neglect to return any value). I would guess that this would have been brought to your attention if you ran the code through the static analyzer ("Analyze" on Xcode's "Product" menu).
A more subtle observation, but I'd probably not rely upon the annotation's subtitle for determining which annotation view to employ, but rather either
have two annotation subclasses, one for bars and one for clubs; or
have a custom property in your existing Annotation class that indicates whether it's a bar or club (and I'd probably use an enum for that).
At some future date, you might want to use the callout's subtitle for something other than "Bar" vs "Club" (e.g., maybe the address of the bar/club?), and the current model seems to conflate a UI attribute (i.e. what shows up in the callout) with a state property (i.e. a variable that controls which annotation view type to use). Not a big deal, but just an suggestion.

MKPolyline polylineWithPoints bug?

I want to display a route from my location to a destination.
I took this code http://code.google.com/p/octomapkit and I have added a few logging messages.
Go got the route coordinates ( around 103) properly. They are on the way and filling the route from my location to destination, so the google call and parsing the elements is good.
But when I want to display in MKMapView than it shows only the starting the polyline. Like 15 or 20 not more.
I will try to post the code from top to bottom:
The original code took the first element only and I was thinking maybe if I get the last I will see something else, if yes, than I will add all overlays - that's why the for loop.
otherwise : MKPolyline *polyLine = [self.mapView.overlays objectAtIndex:0];
#pragma mark MKMapViewDelegate
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
{
MKPolylineView *routeLineView = nil;
// should take the objectAtIndex:0 , but for test I will check if it has more
for(int i=0; i <self.mapView.overlays.count; i++ ){
MKPolyline *polyLine = [self.mapView.overlays objectAtIndex:i];
routeLineView = [[[MKPolylineView alloc] initWithPolyline:polyLine] autorelease];
routeLineView.fillColor = [UIColor redColor];
routeLineView.strokeColor = [UIColor redColor];
routeLineView.lineWidth = 3;
}
return routeLineView;
}
-(void) routeLoadSucceededWithRoutePoints:(MKMapPoint*)routePoints count:(int)pointNumber {
//NSLog(#"MKMapVew+OctoRoute.routeLoadSucceededWithRoutePoints count: %d", pointNumber);
MKPolyline* routeLine = nil;
routeLine = [MKPolyline polylineWithPoints:routePoints count:pointNumber];
// add the overlay to the map
if (nil != routeLine) {
// added zoom support:
if(shouldZoom){
MKCoordinateRegion region = [self coordinateRegion];
[self setRegion:region animated:YES];
}
//[self removeOverlays:self.overlays];
[self addOverlay:routeLine];
}
}
the //[self removeOverlays:self.overlays]; has no effect if is commented or not, Iwas hoping it will create more :) -but not.
Inside mapPointCArrayFromJSONString I see the coordinates properly:
-(void) jsonLoadSucceededWithData:(NSData*)loadedData {
self.routeParser.jsonStr = [[[NSString alloc] initWithData:loadedData encoding:NSUTF8StringEncoding] autorelease];
MKMapPoint *mapPointCArray = [self.routeParser mapPointCArrayFromJSONString];
//NSLog(#"OctoRouteService.jsonLoadSucceededWithData : %d"+ mapPointCArray.);
[delegate routeLoadSucceededWithRoutePoints:mapPointCArray count:[self.routeParser numberOfPoints]];
}
The steps has the coordinated for sure. Checked many times.
-(MKMapPoint*) mapPointCArrayFromJSONString {
NSArray *steps = [self routeStepsArrayFromJSONString];
//NSLog(#"OctoRouteParser.mapPointCArrayFromJSONString steps:%d ", steps.count);
if(steps.count == 0){
return nil;
}
MKMapPoint *mapPointCArray = malloc(sizeof(CLLocationCoordinate2D) * [steps count]*2 -1);
numberOfPoints = [steps count]-1;
int index=0;
for (NSDictionary *stepDict in steps) {
[self addRouteStepDict:stepDict toMapPointCArray:mapPointCArray atIndex:index];
index = index+2;
}
return mapPointCArray;
}
I can't see a reason why is only the first fraction of the route on my map, with red line.
Any suggestion?
The viewForOverlay delegate method will be called by the map view for each overlay it needs to display a view for. It may also call it more than once for each overlay.
Your code only needs to worry about creating and returning a view for the single overlay passed as a parameter to that method.
The code there should be something like this:
MKPolylineView *routeLineView = [[[MKPolylineView alloc] initWithPolyline:overlay] autorelease];
routeLineView.fillColor = [UIColor redColor];
routeLineView.strokeColor = [UIColor redColor];
routeLineView.lineWidth = 3;
return routeLineView;
The existing code in your question returns the view corresponding to the last overlay that happens to be in the overlays array for every overlay the map view calls viewForOverlay for.
Additionally, that octomapkit has a bug in the mapPointCArrayFromJSONString method. These lines:
MKMapPoint *mapPointCArray = malloc(sizeof(CLLocationCoordinate2D)
* [steps count]*2 -1);
numberOfPoints = [steps count]-1;
should be:
MKMapPoint *mapPointCArray = malloc(sizeof(CLLocationCoordinate2D)
* [steps count]*2);
numberOfPoints = [steps count]*2;
The original first line is wrong because it excludes the end point of the last line segment.
The original second line is very wrong because numberOfPoints is supposed to reflect the number of points in the mapPointCArray (not the last index in the steps array). The way it was, the overlay would only show half the route.
It would be cleaner to change that code so the calculation is done only once:
numberOfPoints = [steps count]*2;
MKMapPoint *mapPointCArray = malloc(sizeof(CLLocationCoordinate2D)
* numberOfPoints);
The viewForOverlay method should still be coded as explained earlier. It should only work with the overlay parameter passed to it and not directly with the map view's overlays array.

Resources