Not working drawing on MapKit? - ios

I'm new to iOS programming. I am trying to draw one line between two points not more than one line. This is what I tried so far;
#property (nonatomic, strong) MKPolylineView *lineView;
#property (nonatomic, strong) MKPolyline *line;
Create a polyline all location ;
-(void)allLocationRoute {
CLLocationCoordinate2D coordinates[record.toMoments.count];
int i = 0;
for (MomentEntity *currentEntity in record.toMoments.allObjects) {
coordinates[i].latitude = [currentEntity.latitude doubleValue];
coordinates[i].longitude = [currentEntity.longitude doubleValue];
i++;
}
MKPolyline *polyline = [MKPolyline polylineWithCoordinates:coordinates count:record.toMoments.allObjects.count];
[self.mapView addOverlay:polyline];
line = polyline;
}
MapView:
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id)overlay {
if ([overlay isKindOfClass:[MKPolyline class]]) {
self.lineView = [[MKPolylineView alloc]initWithPolyline:(MKPolyline*)overlay] ;
self.lineView.strokeColor = [[UIColor redColor] colorWithAlphaComponent:1];
self.lineView.lineWidth = 1;
return self.lineView;
}
return nil;
}
But as you can see from first picture red line makes zig-zag. Any help appreciated.

Related

overlay map view not showing up

I'm trying to make a MKMapView and add and overlay to it using coordinates.
It is not showing up in the mapView.
it seems to be compiling ok but when I open the mapView view in the storyboard I see the map of the world but there is no red overlay anywhere.
Here is my code.
my header
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import <AVFoundation/AVFoundation.h>
#import <CoreMotion/CoreMotion.h>
#import <MapKit/MapKit.h>
NS_ASSUME_NONNULL_BEGIN
#interface mapViewController : UIViewController<CLLocationManagerDelegate,MKMapViewDelegate>
#property (nonatomic, retain) IBOutlet MKMapView *mapView;
#property(nonatomic, retain) MKPolygon *polygon;
#end
and my .m file
#import "mapViewController.h"
#interface mapViewController ()
#end
#implementation mapViewController
#synthesize mapView,locationManager,polygon;
- (void)viewDidLoad {
[super viewDidLoad];
mapView.delegate = self;
NSDictionary *d1=[NSDictionary dictionaryWithObjectsAndKeys:#"37.57111111",#"x",#"-109.52166667",#"y",nil];
NSDictionary *d2=[NSDictionary dictionaryWithObjectsAndKeys:#"32.01138889",#"x",#"-109.59000000",#"y",nil];
NSDictionary *d3=[NSDictionary dictionaryWithObjectsAndKeys:#"31.83166667",#"x",#"-111.95416667",#"y",nil];
NSDictionary *d4=[NSDictionary dictionaryWithObjectsAndKeys:#"32.34250000",#"x",#"-115.14333333",#"y",nil];
NSDictionary *d5=[NSDictionary dictionaryWithObjectsAndKeys:#"34.89722222",#"x",#"-115.47611111",#"y",nil];
NSDictionary *d6=[NSDictionary dictionaryWithObjectsAndKeys:#"37.32083333",#"x",#"-116.02027778",#"y",nil];
NSDictionary *d7=[NSDictionary dictionaryWithObjectsAndKeys:#"37.53305556",#"x",#"-114.73416667",#"y",nil];
NSDictionary *d8=[NSDictionary dictionaryWithObjectsAndKeys:#"37.53166667",#"x",#"-114.11277778",#"y",nil];
NSDictionary *d9=[NSDictionary dictionaryWithObjectsAndKeys:#"37.57111111",#"x",#"-109.52166667",#"y",nil];
NSArray *azcoord = [NSArray arrayWithObjects:d1,d2,d3,d4,d5,d6,d7,d8, nil];
CLLocationCoordinate2D coordinates[azcoord.count];
int coordinatesIndex = 0;
for (NSDictionary * c in azcoord) {
double x = [[c valueForKey:#"x"] doubleValue];
double y = [[c valueForKey:#"y"] doubleValue];
CLLocationCoordinate2D coordinate;
coordinate.latitude = y;
coordinate.longitude = x;
//Put this coordinate in the C array...
coordinates[coordinatesIndex] = coordinate;
coordinatesIndex++;
}
polygon = [MKPolygon polygonWithCoordinates:coordinates count:azcoord.count];
[self.mapView addOverlay:polygon];
}
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{
MKPolygonRenderer *renderer = [[MKPolygonRenderer alloc] initWithPolygon:polygon];
renderer.fillColor = [[UIColor redColor] colorWithAlphaComponent:1];
renderer.strokeColor = [[UIColor blackColor] colorWithAlphaComponent:0.7];
renderer.lineWidth = 2;
return renderer;
}
#end
what I am trying to do is draw an overlay for the state of Arizona. I've checked the coordinates and they are correct.
Eventually I want to create overlays for all states.
can anyone see where I'm going wrong?
I figured it out by changing my approach. Here is my code that is working.
first i create a CLLocationCoordinate2D array of my coordinates and make them into a polygon. then add to mapView.
CLLocationCoordinate2D points[7];
points [0] = CLLocationCoordinate2DMake(36.99910000, -109.04520000);
points [1] = CLLocationCoordinate2DMake(31.33460000, -109.05220000);
points [2] = CLLocationCoordinate2DMake(31.33700000, -111.07720000);
points [3] = CLLocationCoordinate2DMake(32.49410000, -114.81360000);
points [4] = CLLocationCoordinate2DMake(36.10660000, -114.75180000);
points [5] = CLLocationCoordinate2DMake(36.21600000, -114.03940000);
points [6] = CLLocationCoordinate2DMake(37.00150000, -114.04820000);
polygon = [MKPolygon polygonWithCoordinates:points count:7];
[self.mapView addOverlay:polygon];
then I render that to the map view.
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{ NSLog(#"YES!!!!!!!!!!!!!!!!!");
MKPolygonRenderer *renderer = [[MKPolygonRenderer alloc] initWithPolygon:polygon];
renderer.fillColor = [[UIColor redColor] colorWithAlphaComponent:0.2];
renderer.strokeColor = [[UIColor blackColor] colorWithAlphaComponent:0.7];
renderer.lineWidth = 1;
return renderer;
}
then I check to see if my location is inside the polygon.
CLLocationCoordinate2D sampleLocation = CLLocationCoordinate2DMake(myLatitude,myLongitude);//13,80 is the latlong of clear colored area of the MKPolygon in the below image.
MKMapPoint mapPoint = MKMapPointForCoordinate(sampleLocation);
CGPoint mapPointAsCGP = CGPointMake(mapPoint.x, mapPoint.y);
for (id<MKOverlay> polygon in mapView.overlays) {
if([polygon isKindOfClass:[MKPolygon class]]){
NSLog(#"YES<<<<<<<<<<<<<<<<<<");
MKPolygon *polygons = (MKPolygon*) polygon;
CGMutablePathRef mpr = CGPathCreateMutable();
MKMapPoint *polygonPoints = polygons.points;
for (int p=0; p < polygons.pointCount; p++){
MKMapPoint mp = polygonPoints[p];
if (p == 0)
CGPathMoveToPoint(mpr, NULL, mp.x, mp.y);
else
CGPathAddLineToPoint(mpr, NULL, mp.x, mp.y);
}
if(CGPathContainsPoint(mpr , NULL, mapPointAsCGP, TRUE)){
NSLog(#"YES?????????????????????????????????");
//do something else
}
CGPathRelease(mpr);
}
}
I at first didn't want to add a map view but then decided I need to and now that I have I like it.

mkmapview image overlay zooming Memory issue in ios

When I am adding a imageOverlay with high resolution image and map zooms image in the map gone and got memory issues.some times my app crashes. How can this be solved?
Here is my code
-(void)addOverlay
{
MapOverlay *overlay = [[MapOverlay alloc] initWithRouteOverlay:self.routeOverlayObj];
[self.mapView addOverlay:overlay];
}
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{
if([overlay isKindOfClass:[MapOverlay class]])
{
mapOverlay = (MapOverlay *)overlay;
NSLog(#"%# %#",routeInfoObj.routeOverlay,[UIImage imageNamed:routeInfoObj.routeOverlay]);
ATTMapOverLayRender *mapOverlayRender = [[ATTMapOverLayRender alloc] initWithOverlay:mapOverlay overlayImage:[UIImage imageNamed:routeInfoObj.routeOverlay] andImageFile:[NSString stringWithFormat:#"%#.png",routeInfoObj.routeOverlay]];
return mapOverlayRender;
}
else
{
MKPolylineRenderer *routeRenderer = [[MKPolylineRenderer alloc] initWithPolyline:routePolyline];
routeRenderer.strokeColor = [UIColor redColor];
routeRenderer.fillColor = [UIColor redColor];
routeRenderer.lineWidth = 5;
return routeRenderer;
}
return nil;
}
and in "ATTMApOVerlayRender.h"
#interface ATTMapOverLayRender : MKOverlayRenderer
- (instancetype)initWithOverlay:(id<MKOverlay>)overlay overlayImage:(UIImage *)overlayImage andImageFile:(NSString *)file;
#property (nonatomic, weak) UIImage *overlayImage;
#end
"ATTMApOVerlayRender.h"
#import "ATTMapOverLayRender.h"
#implementation ATTMapOverLayRender
- (instancetype)initWithOverlay:(id<MKOverlay>)overlay overlayImage:(UIImage *)overlayImage andImageFile:(NSString *)file {
self = [super initWithOverlay:overlay];
if (self) {
self.overlayImage = overlayImage;
}
return self;
}
- (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context {
CGImageRef image = _overlayImage.CGImage;
MKMapRect overlayMapRect = [self.overlay boundingMapRect];
CGRect overlayRect = [self rectForMapRect:overlayMapRect];
// draw image
CGContextScaleCTM(context, 1.0, -1.0);
CGContextTranslateCTM(context, 0.0, -overlayRect.size.height);
CGContextDrawImage(context, overlayRect, image);
}
#end
I'm running into similar problems on a tile overlay project as well.
I was able to significantly improve the memory usage by maintaining a single MKMapOverlayRenderer.
Rather than allocating memory for a new MKOverlayRenderer (or MKPolylineRenderer) every time the mapView: renderForOverlay: method is called, create a class variable and rewrite to it.
So in your ViewController.h or whatever class contains your mapView that calls -(MKOverlayRenderer*)mapView:(MKMapView*)mapView rendererForOverlay:(id<MKOverlay>)overlay have,
#property (nonatomic, strong) MKOverlayRenderer *renderer;
And in the declaration of -(MKOverlayRenderer*)mapView:(MKMapView*)mapView rendererForOverlay:(id<MKOverlay>)overlay
use
self.renderer = [[MKOverlayRenderer alloc] init...

Same MKOverlayView delegate called in one UIView but not another. What's missing?

My app tracks GPS movement as a MKPolyline routepath on a MKMapView as an MKOverlayRenderer in the HomeVC, saves the data, and displays it later, as a saved routepath a few VCs deeper, on DisplayVC. I can confirm that the data is identical to the original data on the second VC, and the proper routeBounds are used when the map is shown, but the OverlayRenderer is never called on the second VC. Why not? I'm thinking delegate problems, but I can't find anything wrong.
Both homeVC.h
#interface homeVC : UIViewController <CLLocationManagerDelegate, MKMapViewDelegate> {
and displayVC.h are the same, except for the name:
#interface displayVC : UIViewController <CLLocationManagerDelegate, MKMapViewDelegate> {
CLLocationManager *locationManager;
// the data representing the route points
MKPolyline* _routePath;
// the view we create for the line on the map
MKPolylineView* _routePathVw;
// the rect that bounds the loaded points
MKMapRect _routeBounds;
}
#property (nonatomic, weak) IBOutlet MKMapView *mapView;
#end
And both homeVC.m and displayVC.m are set up the same:
- (void)viewDidLoad {
[super viewDidLoad];
// Add the Map
[_mapView setDelegate:self];
_mapView.mapType = MKMapTypeStandard;
}
Lots of good-working code here. Then,
-(void) buildRoute {
CLLocationCoordinate2D thisCoord;
int i = [arrayLa count] - 1; // keep growing the array size
MKMapPoint *tmpArr = realloc(pointArr, sizeof(CLLocationCoordinate2D)*(arrayLa.count));
pointArr = tmpArr;
thisCoord.latitude = [[arrayLa objectAtIndex:i] floatValue];
thisCoord.longitude = [[arrayLo objectAtIndex:i] floatValue];
MKMapPoint point = MKMapPointForCoordinate(thisCoord);
pointArr[i] = point;
// Reset Map View Boundaries
if( point.x > ne_Pt.x - 500 ) ne_Pt.x = point.x + 1000;
if( point.y > ne_Pt.y - 500 ) ne_Pt.y = point.y + 1000;
if( point.x < sw_Pt.x + 500 ) sw_Pt.x = point.x - 1000;
if( point.y < sw_Pt.y + 500 ) sw_Pt.y = point.y - 1000;
// create the polyline based on the C-array of map Points
_routePath = [MKPolyline polylineWithPoints:pointArr count:arrayLa.count];
_routeBounds = MKMapRectMake(sw_Pt.x, sw_Pt.y, ne_Pt.x-sw_Pt.x, ne_Pt.y-sw_Pt.y);
// add the routePath overlay to the map, if it isn't empty
if (recState == REC && _routePath != nil) {
// zoom in on the route with the fresh bounding box, routeBounds
[self zoomInOnRoute];
[_mapView addOverlay:_routePath];
}
}
-(void) zoomInOnRoute {
[_mapView setVisibleMapRect:_routeBounds];
}
#pragma mark MKMapViewDelegate
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay {
if ([overlay isKindOfClass:[MKPolyline class]]) {
MKPolyline *route = overlay;
MKPolylineRenderer *routeRenderer = [[MKPolylineRenderer alloc] initWithPolyline:route];
routeRenderer.lineWidth = 3;
routeRenderer.strokeColor = [UIColor redColor];
return routeRenderer;
}
else return nil;
}
Can anyone help solve my problem?
Thanks!
It does look like a delegate issue. Have you tried putting a breakpoint on the addOverLay call just in case the 'if' is skipping it?
I do something similar and all works fine using MKOverlay and MKOverlayRender (based on the apple Breadcrumbs sample app but updated). The app displays a route that the user can save to CoreData. They can select from a table of saved routes and the route is rendered using MKOverlayRenderer.
Set the delegate
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[self.mapView setDelegate:self];
}
Create a MKOverlay and add to mapView
- (void)createRoute2
{
// Some CoreData stuff. Iterate through map points and create an overlay.
// Order by date ascending so we draw in sequential order
NSSortDescriptor *timeStampDescriptor = [[NSSortDescriptor alloc] initWithKey:#"pointDate" ascending:YES];
NSArray *sortDescriptors = #[timeStampDescriptor];
NSArray *routePts = [[self.selectedRoute mapDetail] sortedArrayUsingDescriptors:sortDescriptors];
// A long is a bit excessive just use an int is fine ( BUT might be a huge number of route points)
long nbrPts = routePts.count;
if (nbrPts < 2){
return;
}
CLLocationCoordinate2D mapPointLoc;
MKMapRect updateRect; // The map area
// Init the route
// FtfmapDetail is a managed object holding lat long (and other stuff)
FtfMapDetail *currentPt = (FtfMapDetail *)[routePts objectAtIndex:0];
mapPointLoc = CLLocationCoordinate2DMake([currentPt.latitude floatValue], [currentPt.longitude floatValue]);
// self.route is a subclassed MapOverlay
if (!self.route)
{
// BGSMapOverlay is a subclassed MapOverlay
self.route = [[BGSMapOverlay alloc] initWithCenterCoordinate:mapPointLoc];
[self.mapView addOverlay:self.route];
}
// Add subsequent points. Kick off the for loop at int position 1 not 0
for (int i=1; i <nbrPts; i++){
currentPt = (FtfMapDetail *)[routePts objectAtIndex:i];
mapPointLoc = CLLocationCoordinate2DMake([currentPt.latitude floatValue], [currentPt.longitude floatValue]);
// AddCoordinate is a method in MKOverlay subclass that returns a bounding MKMaprect for all points in MkOverlay
updateRect = [self.route addCoordinate:mapPointLoc];
}
MKCoordinateRegion region = MKCoordinateRegionForMapRect(self.route.boundingMapRectCompleteRoute);
[self.mapView setRegion:region animated:YES];
}
And make sure you add the delegate method
#pragma mark - MKMapView delegate
// self.routeViewRenderer is a sub-classed MKOverlayRendered (based on the Breadcrumbs app from apple CrumbPathView subclassed MKOverlayView)
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay{
if (!self.routeViewRenderer)
{
_routeViewRenderer = [[BGSMKOverlayRender alloc] initWithOverlay:overlay];
}
return self.routeViewRenderer;
}
Or it could be that you are not sending any coordinates to the MkPolyLine. In the following snippet if I uncomment the "NSArray *routeCoordinates = [[NSArray alloc]init];" to send a Nil array to the MKPolyLine then the code will run but the delegate doesn't get called. If routeCoordinates contains points then delegate is called and route displayed.
-(void)buildRouteOverlays
{
for (int i=0; i< _routeHeaders.count;i++)
{
_selectedRoute = (FtfMaps*) [_routeHeaders objectAtIndex:i];
NSLog(#"DEBUG route date : %#", _selectedRoute.dateMap);
NSArray *routeCoordinates = [self arrayRoutePointCoordinates];
// if a nil array is produce then MapOverlayRenerder is not called - nothing to render
// Test this by uncommenting:
// NSArray *routeCoordinates = [[NSArray alloc]init];
NSLog(#"DEBUG number of point in Route : %lu",(unsigned long)routeCoordinates.count);
// Just a quick test only process the first route
if (i==0){
MKPolyline *routePolyLine = [self polyLineFromArray:routeCoordinates];
[self.mapView addOverlay:routePolyLine];
}
}
}
-(MKPolyline*)polyLineFromArray:(NSArray*)routePoints
{
NSInteger pointsCount = routePoints.count;
CLLocationCoordinate2D pointsToUse[pointsCount];
for(int i = 0; i < pointsCount; i++) {
FtfMapDetail *mapPt = (FtfMapDetail *) [routePoints objectAtIndex:i];
pointsToUse[i] = CLLocationCoordinate2DMake([mapPt.latitude doubleValue], [mapPt.longitude doubleValue]);
}
MKPolyline *myPolyline = [MKPolyline polylineWithCoordinates:pointsToUse count:pointsCount];
return myPolyline;
}
#pragma mark MKMapViewDelegate
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay {
if ([overlay isKindOfClass:[MKPolyline class]]) {
MKPolyline *route = overlay;
MKPolylineRenderer *routeRenderer = [[MKPolylineRenderer alloc] initWithPolyline:route];
routeRenderer.lineWidth = 3;
routeRenderer.strokeColor = [UIColor redColor];
return routeRenderer;
}
else return nil;
}

Issues with MKPolyline

I am very new to Xcode and I am facing issues in tracing user path using polyline.
I am getting locations correctly. I am able to add pins properly. However, my polyline method is never called.
Below is my code.
In header file...
#interface Tracker : UIViewController <MKMapViewDelegate, CLLocationManagerDelegate>
{
MKMapView *mapView;
//other declarations
}
Inside implementation file, I have following code. I call, drawPolyline method inside didUpdateLocations method, which is called correctly.
- (void) drawPolyline:(NSArray *)locations
{
NSInteger numberOfLocations = [locations count];
if (numberOfLocations > 1)
{
CLLocationCoordinate2D *locationCoordinate2DArray = malloc(numberOfLocations * sizeof(CLLocationCoordinate2D));
for (int i = 0; i < numberOfLocations; i++)
{
CLLocation* current = [locations objectAtIndex:i];
locationCoordinate2DArray[i] = current.coordinate;
}
self.polyline = [MKPolyline polylineWithCoordinates:locationCoordinate2DArray count:numberOfLocations];
free(locationCoordinate2DArray);
[mapView addOverlay:self.polyline];
[mapView setNeedsDisplay];
}
}
- (MKOverlayView*)mapView:(MKMapView*)mapView viewForOverlay:(id <MKOverlay>)overlay
{
MKPolylineView* polyLineView = [[MKPolylineView alloc] initWithPolyline:self.polyline];
polyLineView.strokeColor = [UIColor blueColor];
polyLineView.lineWidth = 2;
return polyLineView;
}
Your help is highly appreciated. Thanks in advance.
mapView:viewForOverlay: is a delegate method, so you'll need to set the mapview's delegate somewhere. Otherwise, the delegate method will never be called.
[mapView setDelegate:self];

Updating and organizing overlays on an MKMapView

I want to do overlays on an MKMapView. So I created my custom object:
#interface Spot : NSObject
#property int spot_id;
#property CLLocationCoordinate2D coordinate;
#property float radius;
#property NSObject<MKOverlay> * overlay;
- (id) initWithSpotId:(int)spot_id position:(CLLocationCoordinate2D)coordinate andRadius:(float)radius;
#end
There is a backend, that constantly updates the Spots and delivers them to the phone. So I have to:
Check if the currently rendered spots are still valid and there
If yes, have they moved or changed radius? If so, update them (move? / delete + redraw?!)
Delete if they don't exist anymore.
Is there a better way of keeping track of the overlays? Keeping an NSObject<MKoverlay> * reference attached to each spot and constantly reassigning it feels a bit strange to me.
It seems like there are three questions here:
How to detect changes in spots in your server?
The ugly way to do this would be iterate through your spots and see if the coordinate and/or radius changed. A little better would be to have the server update create, modify, and delete timestamps or some other identifier so the client would have the ability to retrieve all creations, modifications, and/or deletions since the last update. Best would be to marry that with some form of push notification, so the client would also be proactively notified of these changes.
This question is difficult to answer in the abstract. It depends a lot upon the capabilities of your server and the nature of the database (e.g. how many "spots", how frequently do they change, etc.). This impacts both the client-server architecture, but also the client implementation.
How to update the map when a spot changes?
This is a far easier question. Insertions and deletions are easy. You just do addOverlay: (or, in iOS 7, addOverlay:level: and removeOverlay:. For updates, while it's inelegant, I think the easiest way is to just remove the old overlay and add it back in and viewForOverlay will take care of the user interface for you.
What is the right structure of the Spot class?
Just as a thought, but it seems duplicative to have your coordinate and radius properties, and then have a id<MKOverlay> overlay object too (because that's presumably a MKCircle with the same two properties). If your overlays are going to be MKCircle objects, it might be easier to just have a Spot class, itself, to conform to MKOverlay:
#interface Spot : NSObject <MKOverlay>
#property (nonatomic) int spot_id;
#property (nonatomic) CLLocationCoordinate2D coordinate;
#property (nonatomic) CLLocationDistance radius;
#property (nonatomic, readonly) MKMapRect boundingMapRect;
- (id) initWithSpotId:(int)spot_id position:(CLLocationCoordinate2D)coordinate andRadius:(CLLocationDistance)radius;
#end
Then, all you need to do is to implement boundingMapRect and intersectsMapRect:
- (MKMapRect) boundingMapRect
{
MKMapPoint point = MKMapPointForCoordinate(self.coordinate);
CLLocationDistance distance = self.radius * MKMetersPerMapPointAtLatitude(self.coordinate.latitude);
MKMapRect rect = MKMapRectMake(point.x, point.y, distance * 2.0, distance * 2.0);
rect = MKMapRectOffset(rect, -distance, -distance);
return rect;
}
- (BOOL)intersectsMapRect:(MKMapRect)mapRect
{
return MKMapRectIntersectsRect(mapRect, [self boundingMapRect]);
}
You might want to double-check that boundingMapRect logic, but I think it's right.
Then you can just add and remove Spot objects as overlays themselves. And all you need to do is to implement a viewForOverlay in your MKMapViewDelegate, for example, in iOS versions prior to 7, that would be:
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay
{
if ([overlay isKindOfClass:[Spot class]])
{
Spot *spot = (id)overlay;
MKCircle *circle = [MKCircle circleWithCenterCoordinate:spot.coordinate
radius:spot.radius];
MKCircleView *overlayView = [[MKCircleView alloc] initWithCircle:circle];
overlayView.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:0.2];
overlayView.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7];
overlayView.lineWidth = 3.0;
return overlayView;
}
return nil;
}
In iOS 7, that would be:
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{
if ([overlay isKindOfClass:[Spot class]])
{
Spot *spot = (id)overlay;
MKCircle *circle = [MKCircle circleWithCenterCoordinate:spot.coordinate
radius:spot.radius];
MKCircleRenderer *renderer = [[MKCircleRenderer alloc] initWithCircle:circle];
renderer.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:0.2];
renderer.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7];
renderer.lineWidth = 3;
return renderer;
}
return nil;
}
Another approach would be to define your Spot as:
#interface Spot : NSObject <MKOverlay>
#property (nonatomic) int spot_id;
#property (nonatomic, strong) MKCircle *overlay;
- (id) initWithSpotId:(int)spot_id position:(CLLocationCoordinate2D)coordinate andRadius:(CLLocationDistance)radius;
And you could then just define boundingMapRect and coordinate return the appropriate values from the MKCircle (saving you from having to write your own):
- (MKMapRect)boundingMapRect
{
return [self.circle boundingMapRect];
}
- (CLLocationCoordinate2D)coordinate
{
return [self.circle coordinate];
}
Clearly the init method would change:
- (id) initWithSpotId:(int)spot_id position:(CLLocationCoordinate2D)coordinate andRadius:(CLLocationDistance)radius;
{
self = [super init];
if (self) {
_spot_id = spot_id;
_circle = [MKCircle circleWithCenterCoordinate:coordinate radius:radius];
}
return self;
}
As would the viewForOverlay (iOS versions prior to 7.0) in the MKMapViewDelegate:
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id<MKOverlay>)overlay
{
if ([overlay isKindOfClass:[SpotCircle class]])
{
SpotCircle *spot = (id)overlay;
MKCircleView *overlayView = [[MKCircleView alloc] initWithCircle:spot.circle];
overlayView.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:0.2];
overlayView.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7];
overlayView.lineWidth = 3.0;
return overlayView;
}
return nil;
}
In iOS 7, that would be:
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{
if ([overlay isKindOfClass:[SpotCircle class]])
{
SpotCircle *spot = (id)overlay;
MKCircleRenderer *renderer = [[MKCircleRenderer alloc] initWithCircle:spot.circle];
renderer.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:0.2];
renderer.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7];
renderer.lineWidth = 3;
return renderer;
}
return nil;
}
I hope that helps.

Resources