缓存切片的 MKTileOverlay 子类

Posted

技术标签:

【中文标题】缓存切片的 MKTileOverlay 子类【英文标题】:MKTileOverlay subclass for cached tiles 【发布时间】:2014-03-15 18:40:50 【问题描述】:

您好,我正在使用MKTileOverlay 在我的ios7 App 中展示 OpenStreetMap 瓷砖。现在我想实现缓存这些图块的能力。我在 NSHipster (http://nshipster.com/mktileoverlay-mkmapsnapshotter-mkdirections/) 上看到了一个帖子,并照做了。

这是我的 MKTileOverlay 子类:

#import "DETileOverlay.h"

@implementation DETileOverlay

- (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:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) 
             result(data, connectionError);
         ];
    


@end

然后我像这样使用它:

#import "DETileOverlay.h"

@interface DEMapViewController : UIViewController <MKMapViewDelegate> 

@property (nonatomic, retain) DETileOverlay *overlay;

-(void)viewDidLoad 
[super viewDidLoad];
    self.overlay = [[DETileOverlay alloc] initWithURLTemplate:@"http://tile.stamen.com/watercolor/z/x/y.jpg"];
        self.overlay.canReplaceMapContent = YES;
        self.overlay.mapView = map;
        [map addOverlay:self.overlay level:MKOverlayLevelAboveLabels];


// iOS 7
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id <MKOverlay>)ovl
    
   MKTileOverlayRenderer *renderer = [[MKTileOverlayRenderer alloc]initWithOverlay:ovl];

        return renderer;
    


    - (void)          mapView:(MKMapView *)mapView
        didUpdateUserLocation:(MKUserLocation *)userLocation
    
        MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(userLocation.location.coordinate, 300, 300);

        [map setRegion:region animated:YES];
    

当我启动我的应用程序时,没有加载任何图块。如果我不覆盖我的子类中的 loadTileAtPath 一切正常。我做错了什么?

非常感谢。

【问题讨论】:

您是否在loadTileAtPath:result: 中设置了断点并检查是否一切正常?数据提取是否有效? 我实际上是这样做的,看起来他总是进入“else”块并尝试通过 NSURLConnection 加载图块。所以问题是为什么他没有正确加载图块,以及为什么他不缓存图块...... 后续问题: 1、数据下载成功了吗? 2. 下载的数据缓存在哪里? 我刚刚从请求中记录了 nsurl,所以这完全没问题。我只是不明白为什么瓷砖没有被加载,因为网址是完全正确的。切片通过 ' [self.cache setObject: data forKey: [self URLForTilePath:path]]; 保存到缓存' 抱歉,我忘了把它包含在我最初的问题中。 data 也不是 nil,connectionError 是 nil。我无法解释为什么瓷砖加载不起作用... 【参考方案1】:

根据您说您已解决的 cmets,但根据您的代码,您永远不会将切片添加到缓存中。没有它,我认为您不会获得任何缓存,并且无论如何都会请求瓷砖。因此,在您的 completionHandler 中,您应该像这样将生成的图块添加到缓存中:

....
 else  
    NSURLRequest *request = [NSURLRequest requestWithURL:[self URLForTilePath:path]];
    [NSURLConnection sendAsynchronousRequest:request queue:self.operationQueue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) 
        // Should inspect the response to see if the request completed successfully!!
        [self.cache setObject:data forKey:[self URLForTilePath:path]];
        result(data, connectionError);
    ];

【讨论】:

【参考方案2】:

我在您的代码中没有看到它,但请务必初始化您的缓存和操作队列。完全使用您的代码是行不通的。当我初始化 MKTileOverlay 时,我设置了它的缓存和操作队列。然后一切正常。

【讨论】:

以上是关于缓存切片的 MKTileOverlay 子类的主要内容,如果未能解决你的问题,请参考以下文章

子类化的 MKTileOverlay 不在地图上显示

带有 MTiles 数据库的 MKTileOverlay

iOS 13.2 MKTileOverlay 偶尔不会渲染

iOS 中的离线地图

将 MKTileOverlay 与 MKPolyLine 一起使用

MKTileOverlay - 添加捆绑瓷砖