Objective-C Mapview only works once - ios

I have a problem with my mapview. When I go to the view it works but when I go to another view and go back to the mapview it doesn't work anymore. I get the right latitude and longitude when I NSLog() it, so that is not the problem.
Code:
- (void) viewDidAppear:(BOOL)animated {
if(IS_IPHONE5) {
mapView = [[MKMapView alloc] initWithFrame:CGRectMake(0,300,320,300)];
} else {
mapView = [[MKMapView alloc] initWithFrame:CGRectMake(0,250,320,250)];
}
mapView.mapType = MKMapTypeStandard;
CLLocationCoordinate2D coord = {.latitude = [testLatitude floatValue], .longitude = [testLongitude floatValue]};
MKCoordinateSpan span = {.latitudeDelta = 0.05, .longitudeDelta = 0.05};
MKCoordinateRegion region = {coord, span};
[mapView setRegion:region];
[self.view addSubview:mapView];
CLLocationCoordinate2D annotationCoord;
annotationCoord.latitude = [testLatitude floatValue];
annotationCoord.longitude = [testLongitude floatValue];
MKPointAnnotation *annotationPoint = [[MKPointAnnotation alloc] init];
annotationPoint.coordinate = annotationCoord;
annotationPoint.title = stringTitle;
[mapView addAnnotation:annotationPoint];
}

based on what you've shown you keep adding map views (a new one each time the VC appears)
you seem to have forgotten to remove it!?

why are you allocating your mapview in viewdidAppear? it will add you map view multiple times on the screen if it is not removed on viewdidDisAppear

In your case you are not removing the map view that is already added , what you can do is use
- (void)viewWillAppear Method to Remove the map like that
- (void)viewWillAppear:(BOOL)animated
{
if(map != nil)
{
[map removeFromSuperview];
}
}
it will removed the previous map view before adding the new map

Add this code to your view:
-(void)viewDidDisappear:(BOOL)animated {
if(mapView)
{
[mapView removeFromSuperview];
}
}
}
Also to remove all subviews:
-(void)viewWillAppear:(BOOL)animated {
for (UIView *view in self.subviews) {
[view removeFromSuperview];
}
}

Try like this it may help
- (void) viewDidAppear:(BOOL)animated {
[super viewDidAppear:(BOOL)animated];
if(IS_IPHONE5) {
if (mapView == nil){
mapView = [[MKMapView alloc] initWithFrame:CGRectMake(0,300,320,300)];
[mapview setDelegate:self];
}
} else {
if (mapView == nil){
mapView = [[MKMapView alloc] initWithFrame:CGRectMake(0,250,320,250)];
[mapview setDelegate:self];
}
}
//Add ramaining Code
}
viewDidDisappear Code
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:(BOOL)animated];
[mapView removeFromSuperview];
mapView = nil;
}
ViewDidAppear: if mapview nil we are creating the mapview otherwise not
viewDidDisappear:if we go outside view we are removing the map

Related

coloring and adding buttons to annotations in a mutable array in iOS

I am coding an application that uses a mapView in iOS.
I am trying to color the annotations in the mutable array to purple and to add a disclosure button to each pin .
The reason that I am using a mutable array is that I am going to retrieve many places from a DB to view each place on the map with a pin.
My code is :
- (void)viewDidLoad{
[super viewDidLoad];
// Do any additional setup after loading the view.
//code of map
[mapMKMapView setMapType:MKMapTypeStandard];
[mapMKMapView setZoomEnabled:YES];
[mapMKMapView setScrollEnabled:YES];
MKCoordinateRegion newRegion = { {0.0, 0.0},{0.0, 0.0}};
newRegion.center.latitude = 12.968427;
newRegion.center.longitude = 44.997704;
newRegion.span.latitudeDelta = 0.004731;
newRegion.span.longitudeDelta = 0.006952;
[self.mapMKMapView setRegion:newRegion animated:YES];
//multiple annotations
NSMutableArray *locations = [[NSMutableArray alloc] init ];
CLLocationCoordinate2D loc;
annotationClass *myAnn;
//1st annotation
myAnn = [[annotationClass alloc] init];
loc.latitude = 12.968427;
loc.longitude = 44.997704;
myAnn.coordinate = loc;
myAnn.title = #"Nakheel2";
myAnn.subtitle = #"This Al-Nakheel 2 stage";
[locations addObject:myAnn];
//2nd annotaion
myAnn = [[annotationClass alloc] init];
loc.latitude = 12.971532;
loc.longitude = 44.998015;
myAnn.coordinate = loc;
myAnn.title = #"Nakheel21";
myAnn.subtitle = #"This Al-Nakheel 2 stage Hi";
[locations addObject:myAnn];
[self.mapMKMapView addAnnotations:locations];
}
//******
-(MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)locations
{
MKPinAnnotationView *MyPin=[[MKPinAnnotationView alloc] initWithAnnotation:locations reuseIdentifier:#"current"];
MyPin.pinColor = MKPinAnnotationColorPurple;
UIButton *adverButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[adverButton addTarget:self action:#selector(button:) forControlEvents:UIControlEventTouchUpInside];
MyPin.rightCalloutAccessoryView = adverButton;
MyPin.draggable = NO;
MyPin.highlighted = YES;
MyPin.animatesDrop = TRUE;
MyPin.canShowCallout = YES;
return MyPin;
}
The viewForAnnotation delegate method will be called by the map view automatically (you don't explicitly "run" it).
The most likely reason the map view is not calling it is that the map view's delegate is not set.
In the storyboard or xib, make sure the map view's delegate outlet is connected to the view controller (right-click or ctrl-click the map view and connect the delegate outlet to the view controller).
Or, you can add this line in the code in viewDidLoad before the setMapType:
//code of map
mapMKMapView.delegate = self; // <-- add this line
[mapMKMapView setMapType:MKMapTypeStandard];
An unrelated point:
Instead of using a custom action method for the button, I suggest using the map view's own calloutAccessoryControlTapped delegate method. In that method, you'll get direct access to the annotation object that was tapped (via view.annotation). Remove the addTarget and the button: method if you decide to use the delegate method.

Not calling MKMapView delegate (mapView:ViewForAnnotation)

I suppose that it's going to be a silly thing but I don't know how to solve it.
First I have to say that my trouble it is because that work sometimes.
I have a main controller which some categories, then touching buttons you can open other view controllers, in this view controllers there are a custom view which contains an mkmapview with annotations.
My problem is that in some categories it deploy the annotations and in the other ones it doesn't.
When it doesn't you can check that the annotations are inside of the MKMapView but it didn't call mapView:ViewForAnnotation until you interact with the map another time.
I will show some code:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
CGRect mapFrame = CGRectMake(0, 0, frame.size.width, frame.size.height);
mapViewDefault = [[MKMapView alloc] initWithFrame:mapFrame];
mapViewDefault.delegate = self;
NSLog(#"Eres delegado!");
CLLocationCoordinate2D initialLocationCoordinate = [DataManager dataManager].centerCoordinate;
[mapViewDefault setCenterCoordinate:initialLocationCoordinate];
MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(initialLocationCoordinate, 3000, 3000);
[mapViewDefault setRegion:viewRegion];
[mapViewDefault setUserInteractionEnabled:NO];
[mapViewDefault setScrollEnabled:NO];
[mapViewDefault setZoomEnabled:NO];
if(TAPIsiOS7()){
[mapViewDefault setRotateEnabled:NO];
}
[self addSubview:mapViewDefault];
}
return self;
}
- (void)addListOfPointsWithNumber:(NSArray*)arrayPoints {
NSLog(#"Añadimos anotación al array anotaciones");
[mapViewDefault removeAnnotations:mapViewDefault.annotations];
for (Place *place in arrayPoints) {
if(![place.coordinate isEqualToString:#"0 0"]){
Annotation *annotation = [[Annotation alloc] init];
annotation.coordinate = place.lCoordinate;
annotation.number = place.number;
annotation.place = place;
[mapViewDefault addAnnotation:annotation];
}
}
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
if([annotation isKindOfClass:[Annotation class]]){
NSLog(#"Añadimos anotación al mapa");
Annotation *annotationMap = (Annotation *)annotation;
NSString *identifier = #"Pin";
UIImage *pinImage = [UIImage imageNamed:#"Pin.png"];
MKAnnotationView *pinView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
pinView.frame = CGRectMake(0, 0, pinImage.size.width, pinImage.size.height);
if (annotationMap.number>0) {
pinImage = [self imageWithView:pinImage andNumber:annotationMap.number];
}
pinView.image = pinImage;
pinView.annotation = annotationMap;
return pinView;
}
}
And 3 images:
I'm pretty sure that this code works great (because I can see that in other categories) and it has to be something with execution times.
If somebody has an idea about what is happening it should be nice.
Thank you all!
You should also be returning something in all cases in your mapView:viewForAnnotation:, whereas you are currently only returning for certain types of annotations. At least return nil and see if that helps -- maybe the warning on this method is preventing some sort of runtime use (though that's a bit of a stretch).

independent actions to map overlays -xcode

how can I add independent actions to map overlays? see my code for example: I am not sure if I should use a loop or an if statement. And if I use If statement how it should be? thank you in advance..
- (void)configureOverlay {
if (self.location) {
[self.mapView removeAnnotations:[self.mapView annotations]];
[self.mapView removeOverlays:[self.mapView overlays]];
radiusSmall = 100;
circleOverlaySmall *overlaysmall = [[circleOverlaySmall alloc] initWithCoordinate:self.location.coordinate radius:radiusSmall];
[self.mapView addOverlay:overlaysmall];
[self updateSmall]; <--this action called
CircleOverlay *overlay = [[CircleOverlay alloc] initWithCoordinate:self.location.coordinate radius:self.radius];
[self.mapView addOverlay:overlay];
GeoQueryAnnotation *annotation = [[GeoQueryAnnotation alloc] initWithCoordinate:self.location.coordinate radius:self.radius];
[self.mapView addAnnotation:annotation];
[self updateLocations]; <--this action called
}
}
just drag the [self uploadSmall]; below the [self updateLocations];

MKCircle-Adding/Removing overlays

Imagine that I have 6 circles. My timer calls first 2 circles in the beginning and overlay them on map view. Then after 2 seconds, it calls other circles and add them on map view. My problem is how to remove previous overlays.I want to see smooth transition for instance radar map.
Make it short, it would like to remove previous overlays and add the new overlays without flickering! Thanks a lot in advance!!.
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize mapView;
#synthesize timer;
#synthesize circle1,circle2,circle3,circle4,circle5,circle6;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
CLLocationCoordinate2D zoomLocation1;
zoomLocation1.latitude=29.830071;
zoomLocation1.longitude=-95.319099;
circle1 = [MKCircle circleWithCenterCoordinate:zoomLocation1 radius:15000];
circle1.title=#"first level";
CLLocationCoordinate2D zoomLocation2;
zoomLocation2.latitude=29.830071;
zoomLocation2.longitude=-95.319099;
circle2 = [MKCircle circleWithCenterCoordinate:zoomLocation2 radius:4000];
circle2.title=#"first level";
CLLocationCoordinate2D zoomLocation3;
zoomLocation3.latitude=29.830071;
zoomLocation3.longitude=-95.319099;
circle3 = [MKCircle circleWithCenterCoordinate:zoomLocation3 radius:6000];
circle3.title=#"second level";
CLLocationCoordinate2D zoomLocation4;
zoomLocation4.latitude=29.830071;
zoomLocation4.longitude=-95.319099;
circle4 = [MKCircle circleWithCenterCoordinate:zoomLocation4 radius:18000];
circle4.title=#"second level";
CLLocationCoordinate2D zoomLocation5;
zoomLocation5.latitude=29.830071;
zoomLocation5.longitude=-95.319099;
circle5 = [MKCircle circleWithCenterCoordinate:zoomLocation5 radius:1000];
circle5.title=#"third level";
CLLocationCoordinate2D zoomLocation6;
zoomLocation6.latitude=29.830071;
zoomLocation6.longitude=-95.319099;
circle6 = [MKCircle circleWithCenterCoordinate:zoomLocation6 radius:13000];
circle6.title=#"third level";
MKCoordinateRegion viewRegion=MKCoordinateRegionMakeWithDistance(zoomLocation1, 60*1609, 60*1609);
MKCoordinateRegion adjustedRegion=[mapView regionThatFits:viewRegion];
[mapView setRegion:adjustedRegion animated:YES];
mapView.mapType=MKMapTypeStandard;
[mapView setDelegate:(id)self];
i=0;
}
- (void)viewDidUnload
{
[self setMapView:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (IBAction)drawButton:(id)sender {
timer = [NSTimer scheduledTimerWithTimeInterval:(2.0) target:self selector:#selector(addingOverlay) userInfo:nil repeats:YES];
}
- (void)addingOverlay {
i=i+1;
switch(i%3)
{
case 1:
[mapView removeOverlays: [mapView overlays]];
[mapView addOverlay:circle1];
[mapView addOverlay:circle2];
break;
case 2:
[mapView removeOverlays: [mapView overlays]];
[mapView addOverlay:circle3];
[mapView addOverlay:circle4];
break;
case 3:
[mapView removeOverlays: [mapView overlays]];
[mapView addOverlay:circle5];
[mapView addOverlay:circle6];
break;
}
}
-(MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay> )overlay
{
MKCircleView *circleView = [[MKCircleView alloc] initWithOverlay:overlay];
if ([overlay.title isEqualToString:#"first level"])
{
circleView.strokeColor = [UIColor redColor];
circleView.lineWidth = 2;
circleView.fillColor=[UIColor yellowColor];
}
else if([overlay.title isEqualToString:#"second level"])
{
circleView.strokeColor = [UIColor whiteColor];
circleView.lineWidth = 2;
circleView.fillColor=[UIColor blackColor];
}
else{
circleView.strokeColor = [UIColor greenColor];
circleView.lineWidth = 2;
circleView.fillColor=[UIColor redColor];
}
return circleView;
}
#end
I just posted this answer to a similar question.
It has a function that I use (drawRangeRings) that draws two circles. In my example, both circles have the same center coordinate, but different radius values, and colors. You could easily change the code to use different center coordinates for each circle if you need that.
Basically, I call drawRangeRings when the center coordinate changes, and it removes the original two circles, and draws two new ones at a different location.
Let me know if this isn't exactly what you needed.
I don't see any flicker when I use this in my app.

Open different websites through pinpoints in mapview

My idea is to have several (maybe as much as 100) pinpoints in a Google map.
I have created a button in the annotation message that appears when I click the pin. I want each pinpoint to be connected to a website. A different website for each pinpoint.
But at the moment I use this:
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view
calloutAccessoryControlTapped:(UIControl *)control
{
[[UIApplication sharedApplication]
openURL:[NSURL URLWithString: #"http://www.google.co.uk"]];
The problem is that with this code, all the pinpoints open the same website.
Is there any way I can specify a web address for each pinpoint?
#import "ViewController.h"
#import "NewClass.h"
#implementation ViewController
#synthesize mapview;
NSString *myString;
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control
{
//[[UIApplication sharedApplication]
//openURL:[NSURL URLWithString: #"http://www.arebikepark.se"]];
NewClass *ann = (NewClass *)view.annotation;
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:ann.website]];
}
-(IBAction)getLocation {
mapview.showsUserLocation = YES;
}
-(IBAction)setMap:(id)sender {
switch (((UISegmentedControl *) sender).selectedSegmentIndex) {
case 0:
mapview.mapType = MKMapTypeStandard;
break;
case 1:
mapview.mapType = MKMapTypeSatellite;
break;
case 2:
mapview.mapType = MKMapTypeHybrid;
break;
default:
break;
}
}
- (void)viewDidLoad {
[super viewDidLoad];
[mapview setMapType:MKMapTypeStandard];
[mapview setZoomEnabled:YES];
[mapview setScrollEnabled:YES];
MKCoordinateRegion region = { {0.0, 0.0 }, {0.0, 0.0 } };
region.center.latitude = 63.399785761795506;
region.center.longitude = 12.91691780090332;
region.span.longitudeDelta = 100.0f;
region.span.latitudeDelta = 100.0f;
[mapview setRegion:region animated:YES];
NewClass *ann = [[NewClass alloc] init];
ann.title = #"Åre";
ann.subtitle = #"www.arebikepark.se";
ann.coordinate = region.center;
ann.website = #"arebikepark.se";
[mapview addAnnotation:ann];
MKCoordinateRegion region1 = { {0.0, 0.0 }, {0.0, 0.0 } };
region1.center.latitude = 61.717050948488904;
region1.center.longitude = 16.153764724731445;
region1.span.longitudeDelta = 100.0f;
region1.span.latitudeDelta = 100.0f;
[mapview setRegion:region1 animated:YES];
NewClass *ann1 = [[NewClass alloc] init];
ann1.title = #"Järvsö";
ann1.subtitle = #"www.jarvsobergscykelpark.se";
ann1.coordinate = region1.center;
ann.website = #"www.jarvsobergscykelpark.se";
[mapview addAnnotation:ann1];
MKCoordinateRegion region2 = { {0.0, 0.0 }, {0.0, 0.0 } };
region2.center.latitude = 57.84191869696362;
region2.center.longitude = 12.02951431274414;
region2.span.longitudeDelta = 100.0f;
region2.span.latitudeDelta = 100.0f;
[mapview setRegion:region2 animated:YES];
NewClass *ann2 = [[NewClass alloc] init];
ann2.title = #"Ale";
ann2.subtitle = #"www.alebikepark.se";
ann2.coordinate = region2.center;
[mapview addAnnotation:ann2];
MKCoordinateRegion region3 = { {0.0, 0.0 }, {0.0, 0.0 } };
region3.center.latitude = 61.17768100166834;
region3.center.longitude = 13.261871337890625;
region3.span.longitudeDelta = 100.0f;
region3.span.latitudeDelta = 100.0f;
[mapview setRegion:region3 animated:YES];
NewClass *ann3 = [[NewClass alloc] init];
ann3.title = #"Kläppen";
ann3.subtitle = #"www.klappen.se/sv/Sommar/Bikepark";
ann3.coordinate = region3.center;
ann3.website = #"www.klappen.se/sv/Sommar/Bikepark";
[mapview addAnnotation:ann3];
MKCoordinateRegion region4 = { {0.0, 0.0 }, {0.0, 0.0 } };
region4.center.latitude = 65.82881853569008;
region4.center.longitude = 15.067813396453857;
region4.span.longitudeDelta = 100.0f;
region4.span.latitudeDelta = 100.0f;
[mapview setRegion:region4 animated:YES];
NewClass *ann4 = [[NewClass alloc] init];
ann4.title = #"Hemavan";
ann4.subtitle = #"www.bikepark.nu";
ann4.coordinate = region4.center;
ann4.website = #"www.bikepark.nu";
[mapview addAnnotation:ann4];
MKCoordinateRegion region5 = { {0.0, 0.0 }, {0.0, 0.0 } };
region5.center.latitude = 63.29058608431198;
region5.center.longitude = 18.7042236328125;
region5.span.longitudeDelta = 100.0f;
region5.span.latitudeDelta = 100.0f;
[mapview setRegion:region5 animated:YES];
NewClass *ann5 = [[NewClass alloc] init];
ann5.title = #"Örnsköldsvik";
ann5.subtitle = #"www.hkbikepark.se";
ann5.coordinate = region5.center;
ann5.website = #"www.hkbikepark.se";
[mapview addAnnotation:ann5];
}
-(MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
MKPinAnnotationView *MyPin =(MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:#"MyPin"];
if (!MyPin) {
MyPin = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"MyPin"];
MyPin.pinColor = MKPinAnnotationColorRed;
MyPin.canShowCallout = YES;
UIButton *details = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
MyPin.rightCalloutAccessoryView = details;
MyPin.canShowCallout = YES;
}
return MyPin;
}
#end
Add a property to your custom annotation class (the one that implements MKAnnotation) that stores the annotation's website. Set this property when you add the annotation to the map:
ann.website = #"http://www.google.co.uk";
[mapView addAnnotation:ann];
Then in the calloutAccessoryControlTapped delegate method, you can access this property:
MyAnnotationClass *ann = (MyAnnotationClass *)view.annotation;
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:ann.website]];
Based on the additional code you posted, the problem is that the website url strings don't have the http:// scheme prefix which the URLWithString method needs to convert the string to a URL. Because the url strings are invalid, the method returns nil which results in the openURL method doing nothing.
So, for example, the lines that set the website property should be:
ann.website = #"http://www.arebikepark.se";
ann1.website = #"http://www.jarvsobergscykelpark.se";
ann2.website = #"http://www.alebikepark.se"; //(line was missing completely)
ann3.website = #"http://www.klappen.se/sv/Sommar/Bikepark";
ann4.website = #"http://www.bikepark.nu";
ann5.website = #"http://www.hkbikepark.se";
Additionally, though the above urls are not a problem, if you intend to use urls with query strings that might contain special characters, you'll also need to escape the url string before passing it. One way is to use the stringByAddingPercentEscapesUsingEncoding method. See this answer by Dave DeLong for an example and some precautions/limitations/alternatives with that method.
Finally, unrelated to your main issue but, here are some additional comments on the code:
You don't need to create a region for each annotation just to set its coordinate. You can just do ann.coordinate = CLLocationCoordinate2DMake(63.399785761795506, 12.91691780090332);
If you are not using ARC, there are several memory leaks.
In viewForAnnotation, you should add an else part to the if statement: else MyPin.annotation = annotation; in case an annotation view is re-used for a different annotation. It probably won't happen with so few annotations but it's logically and technically required.
If you want the user location to appear as a blue dot instead of a red pin, you'll need to add this to the top of the viewForAnnotation method: if ([annotation isKindOfClass:[MKUserLocation class]]) return nil;

Resources