地图离线缓存
Offline Cache of Map
我非常需要为我的应用程序制作离线地图,因为它主要是为泰国制作的,那里通常很难获得互联网连接。我现在正在为我的 MKTileOverlay
使用 OpenStreetMap
,但在实现它以供离线使用时遇到问题。我找到了一个教程,上面写着 MKTileOverlay
的子类。所以,在我的 ViewController
地图所在的地方,我有:
- (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];
}
在我的 MKTileOverlay
子类中,我有:
- (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);
}];
}
}
问题是什么都没有加载,除非我注释掉子类中的代码。我哪里搞砸了?
您似乎没有填充缓存。它总是会是空的?
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);
}];
}
我认为这将解决您的问题。请记住,NSCache 不会持久保存到磁盘(仅保存到内存),因此虽然它在后台运行的应用程序中仍然存在,但如果您想要完全离线功能(可能是 Core Data),您将需要更复杂的东西 运行。
在我们公司,我们选择使用MapBox进行离线映射。
在那里,您可以使用 MapBox Studio 设计和设计您自己的地图,然后将您的地图(在选定的缩放级别范围内)导出到外部文件中。我们的大小约为 40Mb。
从那里,您可以使用 MapBox iOS SDK 轻松地将其添加到您的应用中。
(免责声明:不,我不为他们工作!我们特别选择他们是因为他们能够定义我们自己的 land/sea 颜色和样式,并且能够将地图文件包含在我们的 Xcode 项目,可离线使用。)
我很感激你的确切问题是如何让 OpenStreetMap 自己的地图离线,但我希望这对你有用。
我非常需要为我的应用程序制作离线地图,因为它主要是为泰国制作的,那里通常很难获得互联网连接。我现在正在为我的 MKTileOverlay
使用 OpenStreetMap
,但在实现它以供离线使用时遇到问题。我找到了一个教程,上面写着 MKTileOverlay
的子类。所以,在我的 ViewController
地图所在的地方,我有:
- (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];
}
在我的 MKTileOverlay
子类中,我有:
- (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);
}];
}
}
问题是什么都没有加载,除非我注释掉子类中的代码。我哪里搞砸了?
您似乎没有填充缓存。它总是会是空的?
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);
}];
}
我认为这将解决您的问题。请记住,NSCache 不会持久保存到磁盘(仅保存到内存),因此虽然它在后台运行的应用程序中仍然存在,但如果您想要完全离线功能(可能是 Core Data),您将需要更复杂的东西 运行。
在我们公司,我们选择使用MapBox进行离线映射。
在那里,您可以使用 MapBox Studio 设计和设计您自己的地图,然后将您的地图(在选定的缩放级别范围内)导出到外部文件中。我们的大小约为 40Mb。
从那里,您可以使用 MapBox iOS SDK 轻松地将其添加到您的应用中。
(免责声明:不,我不为他们工作!我们特别选择他们是因为他们能够定义我们自己的 land/sea 颜色和样式,并且能够将地图文件包含在我们的 Xcode 项目,可离线使用。)
我很感激你的确切问题是如何让 OpenStreetMap 自己的地图离线,但我希望这对你有用。