Map Challenge - Memory warning and reinitializing the view


#1

So, after reading the topic on memory warnings and implementing the Map Challenge I decided to see what happened if I simulated a memory warning on the MapViewController.

First time loading the MapView everything work fine, my ‘location’ is shown and the setRegion:animated: method is completed.
I turn to one of the other tabs and simulate a memory warning before tapping the Map tab. The blue circle is added again, but the map does not zoom or move to the region anymore.

- (id)init
{
    self = [super init];
    if (self) {
        UITabBarItem *tabBarItem = [self tabBarItem];
        [tabBarItem setTitle:@"Map"];
    }
    
    return self;
}

- (void)mapView:(MKMapView *)map didUpdateUserLocation:(MKUserLocation *)userLocation {
    NSLog(@"User location updated");
    CLLocationCoordinate2D loc = [userLocation coordinate];
    MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(loc, 250, 250);
    [map setRegion:region animated:YES];
}

-(void)viewDidUnload {
    if([mapView delegate]) [mapView setDelegate:nil];
    [mapView release];
}

The “Shows User Location” property has been set in Interface Builder rather than code and the delegate is linked to my file’s owner.

A follow up question about that delegate. Is it best practice to add another object as the delegate in Interface Builder if it’s the same as the File’s Owner? And if a delegate is set via Interface Builder, as it is in this situation, is it necessary to set it to nil in the viewDidUnload method?


#2

I don’t know what to say, other than I’m seeing the same type of behaviour you are. When I tick the box for Shows User Location in IB, then when the view reloads after the memory warning it shows the blue dot on the map but does not zoom there. When I untick the box but add [worldView setShowsUserLocation: YES] to MapViewController.m’s -viewDidLoad method, then it zooms into the blue dot upon reload after the memory warning. I do not know why the two techniques behave differently.

The -viewDidUnload method posted above seems odd. In -dealloc for example we test to see if the delegate is pointing to self before setting it to nil. If you don’t care where it’s currently pointing, then just set it to nil and be done with it (without testing). The bigger thing would be setting the released variables to nil (mapView in this case) so there’s no danger in later dereferencing a now-invalid address.

I’m afraid I don’t understand the best practice question. (Are you asking if it’s better to set the delegate in IB versus in code?)


#3

Thanks for taking the time to look at this.

The ‘best practice’ question refers to the fact that the delegate for the view is the same object as the ‘first owner’ in Interface Builder. So I have two options, adding an object and giving it the class ‘MapViewController’ to link it as a delegate, or just link to the first owner and make that my delegate. It makes no difference in the end, but it might be that using ‘first owner’ as a delegate for the map would be considered bad practice.

When I untick the box for ‘Shows User Location’ in Interface Builder and add [mapView setShowsUserLocation:YES]; to viewDidLoad the map doesn’t do anything anymore. Not even the first time its loaded. I do see the log, but that’s it.


#4

I’m having the same problem as well. I created the MapKitView programmatically, and no matter what I do, I can’t get the map to zoom after simulating a memory warning. It’s not really making any sense to me why this is not working and I’m very confused. Any help would be greatly appreciated. :confused:


#5

In -viewDidLoad, make sure you (Ziggie, and maybe abnopanda too; no code, so I can’t tell) invoke [super viewDidLoad] before doing anything else.


#6

Ah yes, that was a stupid oversight. I’ve added the super call, but it didn’t help.

-(void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"MapviewDidLoad");
    [mapView setShowsUserLocation:YES];
}

I can see “MapviewDidLoad” in the debugger output, but nothing else happens. One thing I should’ve mentioned before is that I’m using the hackLocationFix provided here, but I don’t think that should make any difference in this situation.

Ah well, it’s not really all that important. I don’t want to take up to much of your time for this.


#7

Interesting. It turns out that if Shows User Location is left checked in IB then it still doesn’t zoom in. So you need the setting in -viewDidLoad, plus the “super” call you added, and Shows User Location to be unchecked in IB before it’ll zoom in after the low memory warning.


#8

Ah yes, I finally got it to work with those settings! Thanks for the help. :slight_smile:


#9

hmm… I created my view programmatically so there’s no IB for me to edit… does that mean that this is only going to work if we use IB to make the connections?

- (void)loadView
{
    NSLog(@"~~~MapViewController's loadView");
    MKMapView *map = [[MKMapView alloc] initWithFrame:CGRectZero];
    NSLog(@"loadview: %@", map);
    [map setDelegate:self];
//    [map setShowsUserLocation:YES];
    [self setView:map];    
    [map release];
}

- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
    NSLog(@"%%%%MapView didUpdateUserLocation");
    
    CLLocationCoordinate2D center = [userLocation coordinate];
    MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(center, 100, 100);
    [mapView setRegion:region animated:YES];
    NSLog(@"MapView didUpdateUserLocation finished");
    
}


- (void)viewDidLoad
{
    [super viewDidLoad];
    NSLog(@"****MapViewController's view didLoad");

    MKMapView *map = (MKMapView *)[self view];
    [map setShowsUserLocation:YES];
}

- (void)viewDidUnload
{
    NSLog(@"----MapViewController's view was unloaded due to memory warning");
    [super viewDidUnload];
}

#10

This code (the post right above mine) should work fine. If it doesn’t (and you see all the right log statements), I’d suggest filing a bug with Apple.