Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Offline Cache of Map

I have a big need to do an offline map for my app, as it is made mostly for Thailand, where internet connection is often hard to come by. I am using OpenStreetMap right now for my MKTileOverlay but am having issues implementing it for offline use. I have found a tutorial that says to subclass MKTileOverlay. So, in my ViewController where the map is I have:

 - (void)viewWillAppear:(BOOL)animated {

    CLLocationCoordinate2D coord = {.latitude =  15.8700320, .longitude =  100.9925410};
    MKCoordinateSpan span = {.latitudeDelta =  3, .longitudeDelta =  3};
    MKCoordinateRegion region = {coord, span};
    [mapView setRegion:region];
}

- (void)viewDidLoad {
    [super viewDidLoad];

    self.title = @"Map";
    NSString *template = @"http://tile.openstreetmap.org/{z}/{x}/{y}.png";
    self.overlay = [[XXTileOverlay alloc] initWithURLTemplate:template];
    self.overlay.canReplaceMapContent = YES;
    [mapView addOverlay:self.overlay level:MKOverlayLevelAboveLabels];
}

- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id)overlay {

    return [[MKTileOverlayRenderer alloc] initWithTileOverlay:overlay];
}

In my subclass of MKTileOverlay, I have:

- (NSURL *)URLForTilePath:(MKTileOverlayPath)path {
    return [NSURL URLWithString:[NSString stringWithFormat:@"http://tile.openstreetmap.org/{%ld}/{%ld}/{%ld}.png", (long)path.z, (long)path.x, (long)path.y]];
}

- (void)loadTileAtPath:(MKTileOverlayPath)path
                result:(void (^)(NSData *data, NSError *error))result
{
    if (!result) {
        return;
    }
    NSData *cachedData = [self.cache objectForKey:[self URLForTilePath:path]];
    if (cachedData) {
        result(cachedData, nil);
    } else {
        NSURLRequest *request = [NSURLRequest requestWithURL:[self URLForTilePath:path]];
        [NSURLConnection sendAsynchronousRequest:request queue:self.operationQueue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
            result(data, connectionError);
        }];
    }
}

The issue is that NOTHING gets loaded at all, unless I comment out the code in the subclass. Where am I messing up?

like image 735
user717452 Avatar asked Aug 09 '16 20:08

user717452


People also ask

Where are offline maps stored?

Offline maps are downloaded on your device's internal storage by default, but you can download them on an SD card instead. If your device is on Android 6.0 or higher, you can only save an area to an SD card that's set up for portable storage. To learn how to set up your SD card, get help from your phone's manufacturer.

Do Offline maps save data?

Google Maps allows you to download maps for offline use, helping you save on mobile data when you're out and about. The option to save maps for later is especially helpful when network coverage is sparse — like when you are travelling or in a place with dampeners.

Can Google Maps track offline?

After you download an area, use the Google Maps app just like you normally would. If your internet connection is slow or absent, your offline maps will guide you to your destination as long as the entire route is within the offline map.

Can I delete map cache?

The map image layer whose cache tiles you want to delete. You can choose it by browsing to the desired service in Portal or you can drag and drop a web tile layer from the Project pane Portal tab to supply this parameter. The map image layer whose cache tiles you want to delete.


2 Answers

In our company, we chose to use MapBox for our offline mapping.

There, you can design and style your own maps using MapBox Studio, then export your maps (at a chosen range of zoom levels) into an external file. Ours is about 40Mb in size.

From there, you can use the MapBox iOS SDK to easily add it to your app.

(Disclaimer: no, I don't work for them ! We specifically chose them for the ability to define our own land/sea colors and styling, and the ability to have the map files included in our Xcode project, and usable offline.)

I do appreciate your exact question was how to get OpenStreetMap's own maps to be offline, but I hope this is useful to you.

like image 148
Mike Gledhill Avatar answered Sep 21 '22 05:09

Mike Gledhill


It looks like you're not populating the cache. It's always going to be empty?

if (cachedData) {
    result(cachedData, nil);
} else {
    NSURLRequest *request = [NSURLRequest requestWithURL:[self URLForTilePath:path]];
    [NSURLConnection sendAsynchronousRequest:request queue:self.operationQueue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {

        // Instantiate a new cache if we don't already have one.
        if (!self.cache) self.cache = [NSCache new];

        // Add the data into the cache so it's there for next time.
        if (data) {
            [self.cache setObject:data forKey:[self URLForTilePath:path]];
        }

        result(data, connectionError);
    }];
}

I think that'll solve your problem here. Remember that NSCache does not persist to disk (only to memory) so while it does survive the app being backgrounded, you'll need something more complex in the long run if you want total offline capability (probably Core Data).

like image 43
ncke Avatar answered Sep 20 '22 05:09

ncke