iOS mapView sometimes doesn't load to default position

1.5k views Asked by At

I have my mapView set to a default location every time the view is accessed. Sometimes when you access the view, it will be at the correct spot, although sometimes when you access the view, it will be at the mapView's default location, over the ocean south of Africa. How can I make sure it is in the right spot when the view is accessed.

Here is my code:

-(void)viewDidLoad {

    [super viewDidLoad];

    self.mapView.delegate = self;

    MKCoordinateRegion region = { {0.0, 0.0 }, { 0.0, 0.0 } };
    region.center.latitude = 45.442424;
    region.center.longitude = -122.78;
    region.span.latitudeDelta =  0.60;
    region.span.longitudeDelta =  0.60;
    [mapView setRegion:region animated:YES];
}

This is what loads the annotations:

-(void)initXML {

    NSURL *theURL = [NSURL URLWithString:@"http://www.wccca.com/PITS/"];
    NSData *data = [[NSData alloc] initWithContentsOfURL:theURL];
    xpathParser = [[TFHpple alloc] initWithHTMLData:data];
    NSArray *elements = [xpathParser searchWithXPathQuery:@"//input[@id='hidXMLID']//@value"];
    if (elements.count >= 1) {

        TFHppleElement *element = [elements objectAtIndex:0];
        TFHppleElement *child = [element.children objectAtIndex:0];
        NSString *idValue = [child content];

        NSString *idwithxml = [idValue stringByAppendingFormat:@".xml"];
        NSString *url = @"http://www.wccca.com/PITS/xml/fire_data_";
        NSString *finalurl = [url stringByAppendingString:idwithxml];

        xmlParser = [[XMLParser alloc] loadXMLByURL:finalurl];

        if (xmlParser.calls.count == 0) {

            [self noCallsMessage];
        }
        else {

            [self wcccaAnn];

            NSArray *callsArray = [xmlParser calls];

            for (JointCAD *call in callsArray) {
                NSString *callnumber = [call.callnumber stringByAppendingFormat:@". "];
                NSString *callandnumber = [callnumber stringByAppendingString:call.currentCallType];
                Annotation *ann = [[Annotation alloc] init];
                ann.title = callandnumber;
                ann.subtitle = [call location];
                ann.coordinate = CLLocationCoordinate2DMake([call.latitude doubleValue], [call.longitude doubleValue]);
                [mapView addAnnotation:ann]; }
            }
        }
    }

MKAnnotationView:

-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {

    if ([annotation isKindOfClass:[MKUserLocation class]])
        return nil;

    MKPinAnnotationView *MyPin=[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"current"];
    MyPin.pinColor = MKPinAnnotationColorRed;

    MyPin.draggable = NO;
    MyPin.highlighted = YES;
    MyPin.animatesDrop= YES;
    MyPin.canShowCallout = YES;

    return MyPin;
}
3

There are 3 answers

1
Craig On

There is only one point in the code you have above that set the maps the map location (setRegion). If your map is being set to a different location it isn't in the code you have provided.

4
J2theC On

You are updating the map on a queue different than the main queue. You are lucky your application is not crashing all over the place. Move the view manipulation to the main thread and see if you keep getting the same problem.

edit: if you really have to use a queue to get that span, just do this with the view:

dispatch_async(dispatch_get_main_queue(), ^{
    [mapView setRegion:region animated:YES]; 
});
1
robfeldmann On

I had the same problem and the following solution (applied to your code) worked for me:

-(void)viewDidLoad {

    [super viewDidLoad];

    self.mapView.delegate = self;

    double delayInSeconds = 0.5;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, int64_t)(delayInSeconds * NSEC_PER_SEC));
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
        MKCoordinateRegion region = { {0.0, 0.0 }, { 0.0, 0.0 } };
        region.center.latitude = 45.442424;
        region.center.longitude = -122.78;
        region.span.latitudeDelta =  0.60;
        region.span.longitudeDelta =  0.60;
        [mapView setRegion:region animated:YES];
    });
}

Basically, you wrap the code that sets the region in a block and call that block after delayInSeconds. I found 0.5 enough of a delay in the simulator, but you should test on your slowest device.

If you don't want to use blocks, you could also wrap the region setting code in a separate method and call something like [self performSelector:@selector(nameOfMethod) withObject:nil afterDelay:0.5f];.

The map will start to load and then quickly animate to the set region. If you don't like this animation then be sure to set the animated parameter to NO.