我想显示并缓存地图图块以供从所选服务(例如 Open Street Maps)中离线使用。这似乎很容易,因为iOS7
它可以使用:
static NSString * const template = @"http://tile.openstreetmap.org/{z}/{x}/{y}.png";
self.tileOverlay = [[ZSSTileOverlay alloc] initWithURLTemplate:template];
self.tileOverlay.canReplaceMapContent = YES;
[self.mapView addOverlay:self.tileOverlay level:MKOverlayLevelAboveLabels];
在我的MKTileOverLay
子类中,我重写loadTileAtPath:result:
了下载磁贴并将它们保存到磁盘以供离线使用。后面我会实现一个方法让用户选择下载地图的哪个部分:
- (void)loadTileAtPath:(MKTileOverlayPath)path result:(void (^)(NSData *tileData, NSError *error))result {
NSString *url = [NSString stringWithFormat:@"http://tile.openstreetmap.org/%li/%li/%li.png", (long)path.z, (long)path.x, (long)path.y];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (data == nil) {
// Load a default tile here
} else {
UIImage *image = [[UIImage alloc] initWithData:data];
result(data, nil);
NSString *pathForWritting = [self pathToWriteImage:path];
NSString *fileName = [NSString stringWithFormat:@"%li", (long)path.y];
[self saveImage:image withFileName:fileName ofType:@"png" inDirectory:pathForWritting];
}
}];
}
- (void)saveImage:(UIImage *)image withFileName:(NSString *)imageName ofType:(NSString *)extension inDirectory:(NSString *)directoryPath {
// Create folder structure if it doesn't exist
if (![[NSFileManager defaultManager] fileExistsAtPath:directoryPath]) {
NSError *error = nil;
[[NSFileManager defaultManager] createDirectoryAtPath:directoryPath withIntermediateDirectories:YES attributes:nil error:&error];
if (error) {
NSLog(@"ERROR: %@", error.localizedDescription);
}
}
if ([[extension lowercaseString] isEqualToString:@"png"]) {
NSString *fullPath = [directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", imageName, @"png"]];
[UIImagePNGRepresentation(image) writeToFile:fullPath atomically:YES];
} else if ([[extension lowercaseString] isEqualToString:@"jpg"] || [[extension lowercaseString] isEqualToString:@"jpeg"]) {
[UIImageJPEGRepresentation(image, 1.0) writeToFile:[directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", imageName, @"jpg"]] options:NSAtomicWrite error:nil];
}
}
- (NSURL *)applicationDocumentsDirectory {
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory
inDomains:NSUserDomainMask] lastObject];
}
- (NSString *)pathToWriteImage:(MKTileOverlayPath)path {
NSString *pathFolder = [NSString stringWithFormat:@"tiles/%li/%li", (long)path.z, (long)path.x];
return [NSString stringWithFormat:@"%@/%@", [self applicationDocumentsDirectory].path, pathFolder];
}
这完全符合我的预期,并将图像保存到适当命名的文件夹中:
现在,这里真正的问题是三个方面:
- 将磁贴保存到磁盘,然后在离线时将它们加载回来是个好主意吗?还是应该将它们保存在 SQL Lite DB 之类的东西中?
- 貌似图块是自动加载的
MapKit
,为什么要第二次下载loadTitleAtPath:
呢?有没有办法得到MKMapView
已经加载的瓷砖? - 什么是允许用户选择他们想要下载地图的哪些部分以及地图级别的好方法(忽略我在这里是如何做到的,那是为了测试)?所有缩放级别都高于当前缩放级别的当前矩形?