Search code examples
iosgoogle-maps-sdk-ios

Trying to Preload Google Maps View


I have a Google Map View in a view controller inside of a navigation controller that is on a tabbar controller. Everything works as it should but the load times on the map range from 5-10 seconds when I initially tap on the Map tab.

storyboard-layout

I've come across several StackOverflow posts which list the following method of preloading a tab:

for (UIViewController *viewController in self.tabBarController.viewControllers)
{
    [viewController view];
}

I've modified it to my particular implementation.

for (UIViewController *viewController in self.tabBarController.viewControllers)
{
    UINavigationController *navCon = (UINavigationController*)viewController;
    for (UIViewController *vc in navCon.viewControllers) {
        if ([[NSString stringWithFormat:@"%@",vc.class]  isEqual: @"MapViewController"]){
            MapViewController *mv = (MapViewController*) vc;
            [mv view];
        }

    }
}

Unfortunately, neither implementation preloads the map tab.

Specs

  • Google Maps SKD 1.7.2
  • iOS SDK 7.1

Edit ViewDidLoad on the MapViewController.m

- (void)viewDidLoad
{
    [super viewDidLoad];
    mapView_ = [GMSMapView mapWithFrame:self.view.bounds camera:nil];
    mapView_.delegate = self;
    AppDelegate *appDelegate=(AppDelegate *)[UIApplication sharedApplication].delegate;
    CLLocationCoordinate2D loc=appDelegate.locationManager.location.coordinate;

    GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:loc.latitude
                                                            longitude:loc.longitude
                                                                 zoom:12];
    [mapView_ setCamera:camera];
    mapView_.myLocationEnabled=YES;
    mapView_.settings.myLocationButton = YES;
    self.view = mapView_;
}

Solution

  • I'd suggest just using a container view (long how-to ) which is very easy; it will then reliably work independently. If you wish, simply move it offscreen while it is loading (perhaps slide it in afterwards).

    Note that inside the container view, say the "parent" is of class Boss,

    @implementation SomeContaineredView
    -(void)allTheDataLoaded
        {
        [(Boss*)self.parentViewController someMethodInBoss];
        }
    @end
    

    it's that easy to talk to the parent class.


    NOTE - if you need to communicate from the parent to the containered view, it's very easy if you know the "silly trick" that Apple makes you do .. https://stackoverflow.com/a/15706092/294884

    It's a bit whacky, for such a basic operation you do pretty all the time. You do it in prepareForSegue: like this...

    -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
        {
        if ([segue.identifier isEqualToString:@"containerLogin"])
            self.vcLogin = (LoginVC *)segue.destinationViewController;
    
        if ([segue.identifier isEqualToString:@"containerStartNew"])
            self.vcStartNew = (StartNewVC *)segue.destinationViewController;
    
        }
    

    In the example there are two container views. (With identifiers "containerLogin" and "containerStartNew") So, I have two properties (self.vcLogin, self.vcStartNew). That is exactly how you set them.

    Note that prepareForSegue is badly named. It should be called something like "Set up which runs when you have an embed segue" I explain this at length here: https://stackoverflow.com/a/24351813/294884

    Important! ...

    Here's a handy macro!!!

    #define seg(A, B, C) if ([segue.identifier isEqualToString:A]) \
                               B = (C *)segue.destinationViewController;
    

    In every project we work on, we use that macro.

    Then you can simply write this:

    -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
        {
        seg(@"cOverlayBuy", self.rockets, Rockets);
        seg(@"cOverlayMainMenu", self.overlayMainMenu, OverlayMainMenu);
        
        seg(@"cSearch", self.search, Search);
        seg(@"cMeeting", self.meeting, Meeting);
        
        seg(@"cMeetings", self.meetings, Meetings);
        seg(@"cBooks", self.bikes, Bikes);
        seg(@"cPeople", self.cars, Cars);
        }
    

    Because, these days, every scene has many container views, every single scene we have, for every client, has that code in the "prepareForSegue" call.

    So, once that code runs you can finally "access your container views!"

    [self.cars displayColors:@"red"];
    self.cars.view.hidden=YES;
    [self.meetings calculateNewTimesNow];
    

    ...and so on.

    Like I say, we use this macro in every project. And pretty much every scene has a few container views these days, so it's in every VC! Hope it helps someone.