为缓存的瓦片自定义MKTileOverlay

3
我正在尝试更新我的瓦片地图代码,使用iOS 7的MKTileOverlayMKTileOverlayRenderer,我需要一些指针来使事情更好地运作。
首先,这里是iOS 6的代码:AppleTileOverlay.mTileOverlayView.m。当我用一个与其完全相同但是是MKOverlayRenderer的子类而不是MKOverlayView的类替换TileOverlayView时,它在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}

从返回URL为nil的方法中出现错误信息。

所以问题是:我能否避免这些错误消息,还是应该坚持使用我已有的旧叠加类?


你有没有找到解决办法? - mosca1337
什么都没有。我只是回到了使用基于 https://github.com/mtigas/iOS-MapLayerDemo 的旧瓷砖叠加图层。目前我不知道新版本是否更高效或者有其他更好的原因。 - RL2000
2
顺便说一下,我认为你的文件命名系统存在问题。坐标为x=1 y=11 z=5和x=11 y=1 z=5的瓦片都将被命名为1115.png,而x=1、y=1 z=15也是如此。也许你的瓦片从不与可以交叉的坐标重合,但如果有人将地图视图拉到意想不到的位置,他们可能会得到错误放置的奇怪瓦片。最好在每个参数之间加上下划线,例如1_11_5.png,以避免任何误解。 - Craig
非常好的观点!到目前为止,我还没有遇到这方面的问题,因为我的地图只在小区域内使用,但这将是一个非常简单的修复。好主意! - RL2000
4个回答

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 论坛上的用户 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)); 
            }
        }
    }

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

如果您确定瓦片不存在,则不触发瓦片加载的想法是很好的。


0

当您查看地图上没有瓦片的区域时,是否会出现这种情况?

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


是的,它只适用于文件不存在的URL。我有另一个覆盖类来检查这个。我想在这种情况下最好保留旧的类。 - RL2000
我已经更新了我的解决方案,使用在我的应用程序中。对我来说它运行得非常好,不再有错误消息,但除了视觉比较之外,我还没有测试过它的速度。 - Craig
差点忘了回复你,Craig。谢谢你的建议。我会考虑在某个时候测试一下。目前为止,我已经有的东西似乎足够好用了,所以我还不想改变任何东西 ;) - RL2000
哦,来吧,可能会出什么问题呢?你还有4个月的时间,直到徒步旅行季节真正开始 ;) - Craig

0

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接