I've a viewController (with a mapView) which is included in a tabBarController (my viewController called MapViewController is a section of TabBarController).
My TabBarController is included in a navigationController.
I created the annotationView that are added (via the delegate method MKMapViewDelegate) to the map. I allow the callout to show title and subtitle. Title and subtitle are taken from the queries made to my database. From these queries I get title, details, ID (in string version) and images.
I have no problems in setting up title and subtitle in the callout of each annotation.
But when I set the images for each callout as LeftCalloutAccessoryView, the system puts me all the same image.
And also when I go to click on the RightCalloutAccessoryView (that is a button which push to another viewController) which should open (so push) as a new window navigationController, give me back the wrong ID (ID of another annotation) and therefore are the details wrong in the new window.
I know that maybe explaining it so it is a bit difficult to understand, but instead here's the code:
+ (CGFloat)annotationPadding;
{
return 10.0f;
}
+ (CGFloat)calloutHeight;
{
return 40.0f;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[_mapView setDelegate:self];
_arrPosters = [[NSMutableArray alloc] init];
_script = [[DBGMScr alloc] init]; //Is a class that provides script database connection
//With fieldsRequest I get the array with the field results sought
_arrID = [[NSMutableArray alloc] initWithArray:[_script fieldsRequest:#"SELECT ID FROM Event ORDER BY DateTime DESC"]];
_arrEventNames = [[NSMutableArray alloc] initWithArray:[_script fieldsRequest:#"SELECT Name FROM Event ORDER BY DateTime DESC"]];
_arrEventLatitude = [[NSMutableArray alloc] initWithArray:[_script fieldsRequest:#"SELECT Latitude FROM Event ORDER BY DateTime DESC"]];
_arrEventLongitude = [[NSMutableArray alloc] initWithArray:[_script fieldsRequest:#"SELECT Longitude FROM Event ORDER BY DateTime DESC"]];
_arrEventDescription = [[NSMutableArray alloc] initWithArray:[_script fieldsRequest:#"SELECT Description FROM Event ORDER BY DateTime DESC"]];
for (int i = 0; i < [_arrID count]; i++) {
//With getPoster I get the poster for the event (located on the server) by using a script (it works perfectly), and add it to the array of posters
UIImage *poster = [_script getPoster:_arrID[i]];
[_arrPosters insertObject:poster atIndex:i];
}
for (int i = 0; i < [_arrID count]; i++) {
MKPointAnnotation *aAnnotationPoint = [[MKPointAnnotation alloc] init];
CLLocationCoordinate2D theCoordinate;
theCoordinate.latitude = [_arrEventLatitude[i] doubleValue];
theCoordinate.longitude = [_arrEventLongitude[i] doubleValue];
aAnnotationPoint.coordinate = theCoordinate;
aAnnotationPoint.title = _arrEventNames[i];
aAnnotationPoint.subtitle = _arrEventDescription[i];
// Add the annotationPoint to the map
[_mapView addAnnotation:aAnnotationPoint];
}
}
#pragma mark - MKMapViewDelegate
-(MKAnnotationView*)mapView:(MKMapView*)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
CGRect myRect = CGRectMake(-20, -20, 40, 40);
EventAnnotationView *viewAnno = [[EventAnnotationView alloc] initWithFrame:myRect];
viewAnno.canShowCallout = YES;
UIButton* rightButton = [UIButton buttonWithType:
UIButtonTypeDetailDisclosure];
viewAnno.rightCalloutAccessoryView = rightButton;
UIImageView *iconView = [[UIImageView alloc] initWithFrame:myRect];
iconView.image = defaultImage; //defaultImage for now, but I want to show a different image for each annotation
viewAnno.leftCalloutAccessoryView = iconView;
NSString *viewTitle = [viewAnno.annotation title];
return viewAnno;
}
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
EventViewerViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"EventViewer"];
[self.navigationController pushViewController:controller animated:YES];
NSDictionary *selection = #{#"ID" : _arrID[_eventIndex] //but it get an incorrect ID,
#"eventName" : _arrEventNames[_eventIndex]};
[controller setValue:selection forKey:#"selection"];
}
-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
//_eventIndex is an NSInteger declared in file .h
_eventIndex = [_mapView.annotations indexOfObject:view.annotation];
}
EventAnnotationView is subclass of MKAnnotationView:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// make sure the x and y of the CGRect are half it's
// width and height, so the callout shows when user clicks
// in the middle of the image
CGRect viewRect = CGRectMake(-20, -20, 40, 40);
UIImageView* imageView = [[UIImageView alloc] initWithFrame:viewRect];
// keeps the image dimensions correct
// so if you have a rectangle image, it will show up as a rectangle,
// instead of being resized into a square
imageView.contentMode = UIViewContentModeScaleAspectFit;
_imageView = imageView;
[self addSubview:imageView];
}
return self;
}
- (void)setImage:(UIImage *)image
{
// when an image is set for the annotation view,
// it actually adds the image to the image view
_imageView.image = image;
}
There are several issues here but to answer your two main questions first:
To set leftCalloutAccessoryView to a different image for each annotation, you need to look at some value in the annotation parameter that is passed to the viewForAnnotation delegate method. At the crudest level, you could set the image based on the value of annotation.title (eg. if title is "A" then set image to "1" else if title is "B" then set image to "2" etc).
Tapping on the rightCalloutAccessoryView gives you the wrong Event Id because of this code in didSelectAnnotationView:
_eventIndex = [_mapView.annotations indexOfObject:view.annotation];
The above code assumes that the annotations array that the map view returns will be in the same exact order that you added the annotations in (and that it will only contain annotations that you added which isn't the case if showsUserLocation is YES). This assumption is false. Do not assume the annotations array is in any particular order -- do not rely on its order.
A better solution is to use the annotation object itself that you can access directly from the calloutAccessoryControlTapped delegate method using view.annotation.
Since you need the Event's Id and the default MKPointAnnotation class obviously has no property to store that anywhere, you should create your own class (eg. EventAnnotation) that implements MKAnnotation and add all the event properties you need to know for each annotation. Then, you'll be able to access event-specific values directly using the annotation object in the map view's delegate methods without trying to reference back to your original arrays.
The EventAnnotation class might be declared like this:
#interface EventAnnotation : NSObject<MKAnnotation>
#property (assign) CLLocationCoordinate2D coordinate;
#property (copy) NSString *title;
#property (copy) NSString *subtitle;
#property (copy) NSString *eventId;
//Not sure if your event id is a string.
//Change to "#property (assign) int eventId;" if it's an integer.
#end
Then to create the annotation, create an EventAnnotation instead of MKPointAnnotation:
EventAnnotation *aAnnotationPoint = [[EventAnnotation alloc] init];
CLLocationCoordinate2D theCoordinate;
theCoordinate.latitude = [_arrEventLatitude[i] doubleValue];
theCoordinate.longitude = [_arrEventLongitude[i] doubleValue];
aAnnotationPoint.coordinate = theCoordinate;
aAnnotationPoint.title = _arrEventNames[i];
aAnnotationPoint.subtitle = _arrEventDescription[i];
//store event id in the annotation itself...
aAnnotationPoint.eventId = _arrID[i];
[_mapView addAnnotation:aAnnotationPoint];
Finally, in calloutAccessoryControlTapped (you won't need to implement didSelectAnnotationView), you could do this:
EventViewerViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"EventViewer"];
[self.navigationController pushViewController:controller animated:YES];
//cast the view's annotation object to EventAnnotation...
EventAnnotation *eventAnn = (EventAnnotation *)view.annotation;
NSDictionary *selection = #{#"ID" : eventAnn.eventId,
#"eventName" : eventAnn.title };
[controller setValue:selection forKey:#"selection"];
Another thing you should do in viewForAnnotation is explicitly set the view's annotation property immediately after creating it. Although it may be getting assigned automatically somehow, I'd rather do it explicitly to be safe:
EventAnnotationView *viewAnno = [[EventAnnotationView alloc] initWithFrame:myRect];
viewAnno.annotation = annotation; // <-- add this
Two unrelated points:
Instead of creating a separate array for each event property (Ids, Names, Descriptions, Latitudes, etc), I would highly recommend creating an "Event" class with all those properties and then you could create just one array of Event objects. In fact, you could make this Event class implement MKAnnotation itself (instead of creating two classes Event and EventAnnotation).
The code is executing a separate SQL query for each column. All the queries are identical except for the column retrieved. This could be improved greatly by getting all the columns in a single SQL query (eg. SELECT ID, Name, Latitude, Longitude, Description FROM Event ORDER BY DateTime DESC). I am not familiar with this DBGMScr class but you should really look into it. If the table contains 500 annotations and 5 columns, you are currently retrieving a total of 2500 rows when it could be just 500 in one shot.
Related
I created a custom view and I have a map in it, this is how my view is setup.
- (id)initWithFrame:(CGRect)frame withPackage:(AftershipTracking *)package andLocation:(CLLocation *)location
{
if (self = [super initWithFrame:frame]) {
self = [[[NSBundle mainBundle] loadNibNamed:#"SPShareView" owner:nil options:nil] lastObject];
[self setLabelsWithPackage:package];
_dayLabel.text = _dayLabel.text.uppercaseString;
[self setupMapWithPinLocation:location];
}
return self;
}
Inside of the setupMapWithPinLocation I have this.
- (void)setupMapWithPinLocation:(CLLocation *)location
{
_mapView = [[MKMapView alloc]initWithFrame:CGRectMake(0, 0, 760, 560)];
_mapView.mapType = MKMapTypeStandard;
_mapView.delegate = self;
MKPointAnnotation *annotation = [[MKPointAnnotation alloc] init];
[annotation setCoordinate:location.coordinate];
[_mapView addAnnotation:annotation];
MKCoordinateRegion region = [_mapView regionThatFits:MKCoordinateRegionMakeWithDistance(location.coordinate , 700, 700)];
region.span.latitudeDelta = 3;
region.span.longitudeDelta = 3;
[_mapView setRegion:region animated:NO];
}
However after creating the view, when I look at it in debug I get a blank map that has not been loaded yet, what would be the correct way to go about implementing this? I added the delegate methods for checking if the MapView loaded and they seem to never get called. Also I do not need the map to be interactive, the map can be turned into an image and that would be good.
Based on the comment:
_mapView is already added in the nib
A NIB isn't a magical code-generation tool, it's data. It's loaded once, then its influence is expended. When it was loaded, whatever its mapView described was added to the NIB. I'll bet you have a map view in your nib that _mapView connects to? That's the one that's displaying.
When you do this:
_mapView = [[MKMapView alloc]initWithFrame:CGRectMake(0, 0, 760, 560)];
You:
create a new instance of MKMapView that nobody else knows about;
discard your reference to the map view that is visible on screen.
Whatever you subsequently do to _mapView will have no effect to the one on screen for the same reason that:
int a = 3;
int b = a;
b = 4;
... does not change the value of a. Changing the identity of the object that _mapView points to has no effect on your view hierarchy. Your views are completely unaware that you have done it.
If you have a map view in your NIB that is being created and displaying as you want then there's no reason also to create one programmatically. Delete the line quoted above and leave everything else alone.
(also: it's very odd that you want to call initWithFrame: and then throw away your instance for a NIB-loaded copy, which you decided not to load via -initWithNibName:bundle:; if you're using a NIB then you should just set your basic view properties up in the NIB)
I have to remove all the annotations added to my MKMapView but when I execute :
NSMutableArray *annotationsToRemove = [[NSMutableArray alloc] initWithArray: mapView.annotations];
[mapView removeAnnotations: annotationsToRemove];
The array annotationsToRemove contains a MKUserLocation annotation and it doesn't delete it.
Is there a way to reset the map? I need to delete all the annotations from it!
You can just set the showsUserLocation property of your mapView to NO.
mapView.showsUserLocation = NO;
Actually you can not edit MKUserLocation annotation. I mean you can not remove it from map annotation's array as it is a read-only property of MKMapView.
If you visit MKMapView.h class. You will find below line
#property (nonatomic, readonly) MKUserLocation *userLocation;
Here we can see that this property is a read only. So we can not delete it from MKMapView annotations array. How ever you face difficulties in calculation with other annotations then you can runtime hide it.
What I am trying to explain is when user location is not required any more you can set NO for user location property.
For example with your code:
NSMutableArray *annotationsToRemove = [[NSMutableArray alloc] initWithArray: mapView.annotations];
[mapView removeAnnotations: annotationsToRemove];
[self.mapView setShowsUserLocation:NO];
NSLog(#"MapView annotations :%#", mapView.annotations);
Check NSLog output, you will see that MKUserLocation annotation is removed from mapView.annotations array.
It is the simple way I did follow. How ever I am not sure about there is other way to do this. Please leave a comment if you found any other solution.
In the h insert
#property (weak) MKAnnotationView *ulv;
In the m insert
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated {
MKZoomScale currentZoomScale = mapView.bounds.size.width / mapView.visibleMapRect.size.width;
NSLog(#"current zoom scale is %f",currentZoomScale);
ulv = [mapView viewForAnnotation:mapView.userLocation];
if( currentZoomScale > 0.049 ){
ulv.hidden = YES;
}else{
ulv.hidden = NO;
}
}
i'll try to keep this very simple :
I'm very new to Objective-C (or programming actually) so i'll probably need an explanation more than just an answer.
What i'm trying to do and can't do (yet):
Getting a pin's coordinate after tapping it's disclosure, and eventually pass it through a segue.
Practically, i'm clicking my "info" icon on a pin I just created, and i'd like to see it's info in another page (a webview). This page would show coordinates (and other stuff that we don't need here).
Why :
Practically, i'm clicking my "info" icon on a pin's annotation created earlier by the user, and i'd like to see it's info in another page (a webview). This page would show coordinates (and other stuff that we don't need here).
My pins coordinates are stored into a
CLLocationCoordinate2D location;
I can't re-use the variables i used before because they might be outdated (it would only work if the user asks for the last one created...)
And I do not know how i can get a pin's coordinates ; there must be a method or something but i jsut can't find it. I've found MANY answers on the internet, and none seemed to work, probably because i didn't understand them properly. Anyway, i couldn't use them.
I'll show you bits of my code, it's pretty straight forward i guess :
There is the viewDidLoad, you probably want to see it, i guess :
- (void)viewDidLoad
{
[super viewDidLoad];
name = [[NSString alloc]init];
detail = [[NSString alloc]init];
UILongPressGestureRecognizer *lpgr = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longpressToGetLocation:)];
lpgr.minimumPressDuration = 2.0; //user must press for 2 seconds
[_map addGestureRecognizer:lpgr];
CLLocationCoordinate2D loc = CLLocationCoordinate2DMake(50.837863, 4.353616);
MKCoordinateSpan span = MKCoordinateSpanMake(.035, .035);
MKCoordinateRegion reg = MKCoordinateRegionMake(loc, span);
self.map.region = reg;
[self buildBaseAnno];
self.map.showsUserLocation = true;
}
I know this is important but to be honest i don't fully understand how this bit works ; still, it does work. :D
-(MKAnnotationView*)mapView:(MKMapView*)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
MKAnnotationView* v = nil;
{
static NSString* ident = #"Pin";
v = [_map dequeueReusableAnnotationViewWithIdentifier:ident];
if (v == nil)
{
v = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:ident];
((MKPinAnnotationView*)v).pinColor = MKPinAnnotationColorRed;
UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
v.rightCalloutAccessoryView = infoButton;
v.centerOffset= CGPointMake(0,-20);
v.canShowCallout= YES;
}
v.annotation = annotation;
}
return v;
}
Touch pin creation :
- (void)longpressToGetLocation:(UIGestureRecognizer *)gestureRecognizer
{
if (gestureRecognizer.state != UIGestureRecognizerStateBegan)
return;
CGPoint touchPoint = [gestureRecognizer locationInView:self.map];
location = [self.map convertPoint:touchPoint toCoordinateFromView:self.map];
[self showAlertName];
}
The actual annotation/pin creation method
-(void)buildAnno
{
CLLocationCoordinate2D coordinate;
coordinate.latitude = location.latitude;
coordinate.longitude = location.longitude;
MKPointAnnotation* newann = [MKPointAnnotation new];
newann.coordinate = coordinate;
newann.title = name;
newann.subtitle = detail;
[self.map addAnnotation:newann];
}
Please, do tell if you need more of the code ; i'm not really sure what i can give you, as my code is probably 'correct' (or decent), i just need to actually know how to get the information i need (that is, coordinates and other stuff from the pin i just tapped.)
And i actually don't tap the pin, i tap the disclosure in the pin's annotation. Anyway, That's enough for now !
Once i can catch these coordinates, i believe i'll be able to pass them through the segue as passing Data is already well explained here, but if there is anything 'special', i'd be really glad if you could add it to your explanation because i'm still really uncomfortable with all this and most of the tutorials/guides/links i've found didn't really help me.
Thank you very much for your time and help :)
(Edit : I had found a similar question here but i believe i need extra help/explanation.)
You don't need the gesture recogniser - the map view delegate protocol already has a method that tells you when the callout accessory was tapped calloutAccessoryControlTapped and this method receives the relevant annotationView. The annotationView.annotation property gets you back to the relevant annotation object and then you can access its coordinate property to get the coordinates of the pin.
First, create a new property in your class:
#property CLLocationCoordinate2D tappedCoord;
then implement the delegate method
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
MKPointAnnotation *annotation=(MKPointAnnotation*)view.annotation;
self.tappedcoord=annotation.coordinate;
[self performSegueWithIdentifier:#"detailViewSegue"]; // Use your appropriate segue identifier
}
Then you can access the property in prepareForSegue (again, change to the appropriate segue name and destination view controller class)
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"detailViewSegue" ]){
DetailViewController *dvc=(DetailViewController *)segue.destinationViewController;
dvc.coord=self.tappedCoord;
}
Also, since your MapView is displaying the user's location, there will be an annotation for that. You need to address this in your viewForAnnotation method, returning nil if the annotation isn't one of yours. You can check the class of the annotation to determine this -
-(MKAnnotationView*)mapView:(MKMapView*)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
MKAnnotationView* v = nil;
if ([annotation isMemberOfClass:[MKPointAnnotation class]]) {
static NSString* ident = #"Pin";
v = [_map dequeueReusableAnnotationViewWithIdentifier:ident];
if (v == nil)
{
v = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:ident];
((MKPinAnnotationView*)v).pinColor = MKPinAnnotationColorRed;
UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
v.rightCalloutAccessoryView = infoButton;
v.centerOffset= CGPointMake(0,-20);
v.canShowCallout= YES;
}
v.annotation = annotation;
}
return v;
}
I create an annotation, which contains several elements textbubble and pin. I turn the bubble on when I show annotation, but later I want to shut the bubble off and leave the annotation.
Here are my two methods. The add subview works, but remove subview does not.
-(void)hideETACountdown {
self.etaView.hidden = YES;
[self.etaView removeFromSuperview];
}
-(void)showETACountdown {
self.etaView = [[UIView alloc] initWithFrame:CGRectMake(-34, -97, 89, 59)];
UIImageView *bg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"WaitBubble_backgroundandshadow.png"]];
[self.etaView addSubview:bg];
UILabel *minLabel = [[UILabel alloc] initWithFrame:CGRectMake(7, 24, 42, 21)];
minLabel.text = #"min";
minLabel.textAlignment = UITextAlignmentCenter;
minLabel.font = [UIFont systemFontOfSize:10];
self.etaLabel = [[UILabel alloc] initWithFrame:CGRectMake(13, 4, 30, 27)];
self.etaLabel.font = [UIFont boldSystemFontOfSize:22];
self.etaLabel.textAlignment = UITextAlignmentCenter;
self.etaLabel.text = #"";
[self.etaView addSubview:minLabel];
[self.etaView addSubview:self.etaLabel];
[self addSubview:self.etaView];
self.etaView.hidden = NO;
}
- (id) initWithAnnotation:(id <MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier
{
if (self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier]) {
self.canShowCallout = YES;
self.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
self.innerImage = [[UIImageView alloc] initWithImage:nil];
self.innerImage.frame = CGRectMake(-15, -38, 32, 39);
[self addSubview:self.innerImage];
if(self.showETA) {
[NSNotificationCenter addUniqueObserver:self
selector:#selector(handleEtaTimeUpdate:)
name:kEtaUpdate
object:nil];
[self showETACountdown];
}
}
return self;
}
// UPDATE /////
There seems to be some confusion. This code above is not in the viewController that holds my mkmap, but rather the code inside my custom annotation. Further, I don't want to hide or show the entire annotation based on selecting or deselecting. The self.etaView is custom view which is just part of the annotation. My annotation consists of a custom map pin and an eta bubble. Once the ETA is counted down to 0, I want to remove the bubble (aka self.etaView), but the annotation (map pin) needs to stay on the map the entire time. I just want to hide the ETA bubble.
I am using the proper addAnnotation methods, in the proper way, in my viewController that holds my mkmap. Again, this code above is inside my custom annotation and I want my custom annotation to be responsible for removing its own elements, NOT removing itself from the map.
Come on, why using this weird logics with addSubView and removeFromSuperView. MKMapView is built to support "datasource" for pins. I dunno what kind of view you are trying to acheive but this CGRectMake(-34, -97, 89, 59) looks awful. So please, use method:
-(MKAnnotationView *)mapView:(MKMapView *)aMapView viewForAnnotation:(id<MKAnnotation>)annotation
This way you will have no difficulties managing the annotation using method
- (void)deselectAnnotation:(id < MKAnnotation >)annotation animated:(BOOL)animated
For example:
[mapView deselectAnnotation:[mapView.selectedAnnotations objectAtIndex:0] animated:YES];
The method to remove the bubble was getting called, but it just wasn't getting removed? So what I have done is create notification listener on my annotation and post a notification when I want it removed and it removes it. Not sure why it doesn't just work by calling an instance method?
Anyway, notifications solved it. Need to move on so I can launch the app.
I'm a new guy in the XCode realm and was wondering if someone could help me out.
Essentially, I'm playing around with WWDC2010's TileMap project example and am trying to figure out a way to hide their NOAA chart using a segmented controller.
I can activate the overlay and it displays fine, but I can't for the life of me remove it using a segmented controller.
Here's some code from the header file:
#interface ViewController : UIViewController <MKMapViewDelegate> {
IBOutlet MKMapView *map;
IBOutlet UISegmentedControl *controller;
}
- (IBAction)switchMap:(id)sender;
#end
and here's the code for the .m:
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"initial view loaded");
}
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id)overlay {
TileOverlayView *view = [[TileOverlayView alloc] initWithOverlay:overlay];
view.tileAlpha = 1;
return view;
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (IBAction)switchMap:(id)overlay {
if (controller.selectedSegmentIndex == 0) {
NSLog(#"welp... it loaded...");
[map removeOverlay:overlay];
}
if (controller.selectedSegmentIndex == 1) {
NSLog(#"Map Overlay works");
NSString *tileDirectory = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"Tiles"];
TileOverlay *overlay = [[TileOverlay alloc] initWithTileDirectory:tileDirectory];
[map addOverlay:overlay];
MKMapRect visibleRect = [map mapRectThatFits:overlay.boundingMapRect];
visibleRect.size.width /= 2;
visibleRect.size.height /= 2;
visibleRect.origin.x += visibleRect.size.width / 2;
visibleRect.origin.y += visibleRect.size.height / 2;
map.visibleMapRect = visibleRect;
}
if (controller.selectedSegmentIndex == 2) {
NSLog(#"But... overlay isnt hiding waa");
NSString *tileDirectory = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"Tiles"];
TileOverlay *overlay = [[TileOverlay alloc] initWithTileDirectory:tileDirectory];
[map removeOverlay:overlay]; }
}
In a control action method, the first parameter (no matter what you name it) is always the object that called the method.
Here, the control is a UISegmentedControl so the parameter that gets passed to switchMap: is a reference to that control. In the .h you've declared the parameter with the name sender but in the .m it's named overlay.
Regardless of the name, it's still the segmented control object so passing it to removeOverlay is meaningless and will do nothing.
So in this code:
if (controller.selectedSegmentIndex == 0) {
NSLog(#"welp... it loaded...");
[map removeOverlay:overlay];
}
overlay is pointing to the segmented control and so the removeOverlay does nothing.
In this code:
if (controller.selectedSegmentIndex == 2) {
NSLog(#"But... overlay isnt hiding waa");
NSString *tileDirectory = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"Tiles"];
TileOverlay *overlay = [[TileOverlay alloc] initWithTileDirectory:tileDirectory];
[map removeOverlay:overlay]; }
You are creating a new local overlay object (the compiler is also probably giving you a warning about a local variable hiding the parameter). This new object is separate from the overlay that was already added to the map. Calling removeOverlay on this new object does nothing because this new instance was never added to the map in the first place.
To remove an existing overlay, you either have to keep an ivar reference to it when you add it and pass that ivar to remove or find it in the map view's overlays array.
However, if you will ever have only one overlay, you can pass the first object in the map view's overlays array or just call removeOverlays (plural) and pass the whole array:
if (map.overlays.count > 0)
[map removeOverlay:[map.overlays objectAtIndex:0]];
//OR...
if (map.overlays.count > 0)
[map removeOverlays:map.overlays];