为缓存切片自定义MKTileOverlay

时间:2013-10-16 17:30:16

标签: mapkit mkoverlay

我正在尝试更新我的平铺地图代码以使用iOS 7的MKTileOverlayMKTileOverlayRenderer,我可以使用一些指示来使事情更好。

首先,这是iOS6代码:AppleTileOverlay.mTileOverlayView.m。当我将TileOverlayView替换为一个在所有方面都相同的类时,除了它是MKOverlayRenderer的子类而不是MKOverlayView之外,这在iOS 7中仍能很好地工作。

我正在测试的新作品是MKTileOverlay的子类,唯一的方法是:

-(NSURL *)URLForTilePath:(MKTileOverlayPath)path {
    NSString *tileKey = [[NSString alloc] initWithFormat:@"%d%d%d", path.x, path.y, path.z];
    NSString *tilePath = [[NSBundle mainBundle] pathForResource:tileKey ofType:nil inDirectory:@"TileFolder"];

    NSURL *url;
    if (tilePath) {
        url = [NSURL fileURLWithPath:tilePath];
    }

    return url;
}

地图图块大部分时间都可以正常加载,但是日志填满了这样的消息:

Error loading URL (null): Error Domain=NSURLErrorDomain Code=-1000 "bad URL" UserInfo=0x1b3e19e0 {NSUnderlyingError=0x1894d470 "bad URL", NSLocalizedDescription=bad URL}

从返回nil的方法获取URL。

所以问题是:我可以避免这些错误消息,或者我应该坚持使用旧的覆盖类吗?

4 个答案:

答案 0 :(得分:1)

我认为使用Swift 2.0时, URLForFilePath(...)无法返回 nil ,因为它不是可选的。

我设法使用 MKTileOverlay 子类来解决此问题,以检查上面的有效磁贴路径并加载“假”'如果图块图像不可用,则为透明图块。

override func URLForTilePath(path: MKTileOverlayPath) -> NSURL {

        let tileKey = String(format:"%d/%d/%d",path.z,path.x,path.y)

        let tilePath = NSBundle.mainBundle().pathForResource(tileKey, ofType: "png", inDirectory: "Maps/Map1880")

        let blankTilePath = NSBundle.mainBundle().pathForResource("blank", ofType: "png", inDirectory: "Maps")

        var url: NSURL

        if ((tilePath) != nil)
        {
            url =  NSURL.fileURLWithPath(tilePath!)
        } else {
            url = NSURL.fileURLWithPath(blankTilePath!)
        }

        return url;
    }

这不是很优雅,因为它为每个不属于叠加层的图块加载空白图块。

然而,有一个更好的解决方案,感谢Apple Developer Forum上的用户: junkpile ,尝试加载不存在的覆盖切片的问题是 boundingMapRect 默认设置为 MKMapRectWorld ,即整个世界。

要将此限制为所需的叠加区域,请将子项 MKTileOverlay

以下是一个例子:

import MapKit
class CustomTileOverlay : MKTileOverlay {

        override var boundingMapRect: MKMapRect {
            get {
               //North-East Corner of region
                let lat1 = 53.46075
                let long1 = -1.92618
               //South-West Corner of region
                let lat2 = 53.43018
                let long2 = -1.992885

                //Convert to Coordinates
                let coord1 = CLLocationCoordinate2DMake(lat1,long1)
                let coord2 = CLLocationCoordinate2DMake(lat2,long2)

                //Convert to map points
                let p1 = MKMapPointForCoordinate (coord1);
                let p2 = MKMapPointForCoordinate (coord2);

                //Return the MKMapRect
               return MKMapRectMake(fmin(p1.x,p2.x), fmin(p1.y,p2.y), fabs(p1.x-p2.x), fabs(p1.y-p2.y)); 
            }
        }
    }

答案 1 :(得分:0)

我的猜测是,尽管没有真正有效的url,你总是试图设置tilePath。添加一些调试并查看。

答案 2 :(得分:0)

当您查看地图上没有瓷砖的区域时会发生这种情况吗?

因为您检查是否有该文件,然后如果该文件不存在则不设置url,则返回nil。您应该将有效的NSURL返回到透明图像。

答案 3 :(得分:0)

您可以通过创建自定义MKTileOverlay子类来避免它,如下所示:

@interface MyTileOverlay : MKTileOverlay
@end

@implementation MyTileOverlay

- (NSURL *)URLForTilePath:(MKTileOverlayPath)path 
{
    NSString *tileKey = [[NSString alloc] initWithFormat:@"%d%d%d", path.x, path.y, path.z];
    NSString *tilePath = [[NSBundle mainBundle] pathForResource:tileKey ofType:nil inDirectory:@"TileFolder"];

    NSURL *url;
    if (tilePath) 
    {
        url = [NSURL fileURLWithPath:tilePath];
    }

    return url;
}

- (void)loadTileAtPath:(MKTileOverlayPath)path result:(void (^)(NSData *, NSError *))result
{
    NSURL *url = [self URLForTilePath:path];
    if (url)
    {
        [super loadTileAtPath:path result:result];
    }
}

@end

如果您确定磁贴不存在,那么我们的想法是不会触发磁贴加载。