Tom*_*ift 8 mapkit mkmapview ios mkoverlay
我正在使用自定义功能MKOverlay/MKOverlayView用我自己的磁贴完全覆盖Google底图,这些磁贴是异步加载的.当我收到canDrawMapRect:zoomScale:对覆盖视图的调用(并在这种情况下返回FALSE)时,我遵循请求卸载的tile的模式,然后setNeedsDisplayInMapRect:zoomScale:在tile可用时调用.
这一切通常都有效,并且似乎在模拟器中完美运行.
然而,在设备上我有时会在覆盖层中出现一个"洞" - 缺少一块瓷砖.
我可以看到请求了磁贴,并且请求完成了.我可以看到我打电话setNeedsDisplayInMapRect:zoomScale:,而我传递原来MKMapRect和MKZoomScale它是在提供canDrawMapRect:zoomScale:.但我也可以看到覆盖层永远不会被要求重绘那个图块(既canDrawMapRect:zoomScale:不会drawMapRect:zoomScale:inContext:也不会再次调用该图块).
我需要了解为什么会发生这种情况以及如何纠正它.
这是我的MKOverlayView子类的相关代码:
- (BOOL) canDrawMapRect: (MKMapRect) mapRect zoomScale: (MKZoomScale) zoomScale
{
NSUInteger zoomLevel = [self zoomLevelForZoomScale:zoomScale];
CGPoint mercatorPoint = [self mercatorTileOriginForMapRect:mapRect];
NSUInteger tilex = floor(mercatorPoint.x * [self worldTileWidthForZoomLevel:zoomLevel]);
NSUInteger tiley = floor(mercatorPoint.y * [self worldTileWidthForZoomLevel:zoomLevel]);
NSURL* tileUrl = [self tileURLForZoomLevel: zoomLevel tileX: tilex tileY: tiley];
ASIHTTPRequest* tileRequest = [ASIHTTPRequest requestWithURL: tileUrl];
tileRequest.downloadCache = [ASIDownloadCache sharedCache];
[tileRequest setCacheStoragePolicy:ASICachePermanentlyCacheStoragePolicy];
if ( NO == [[ASIDownloadCache sharedCache] isCachedDataCurrentForRequest: tileRequest] )
{
[tileRequest setCachePolicy: ASIAskServerIfModifiedWhenStaleCachePolicy];
tileRequest.delegate = self;
tileRequest.userInfo = [NSDictionary dictionaryWithObjectsAndKeys:
[NSValue value: &mapRect withObjCType: @encode( MKMapRect )], @"mapRect",
[NSValue value: &zoomScale withObjCType: @encode( MKZoomScale )], @"zoomScale",
[NSNumber numberWithInt: tilex], @"tilex",
[NSNumber numberWithInt: tiley], @"tiley",
nil];
[_tileRequestStack addOperation: tileRequest];
NSLog( @"canDrawMapRect: %d, %d - REQUESTING", tilex, tiley );
return NO;
}
NSLog( @"canDrawMapRect: %d, %d - READY", tilex, tiley );
return YES;
}
- (void) drawMapRect: (MKMapRect) mapRect zoomScale: (MKZoomScale) zoomScale inContext: (CGContextRef) context
{
NSUInteger zoomLevel = [self zoomLevelForZoomScale:zoomScale];
CGPoint mercatorPoint = [self mercatorTileOriginForMapRect:mapRect];
NSUInteger tilex = floor(mercatorPoint.x * [self worldTileWidthForZoomLevel:zoomLevel]);
NSUInteger tiley = floor(mercatorPoint.y * [self worldTileWidthForZoomLevel:zoomLevel]);
NSLog( @"drawMapRect: %d, %d", tilex, tiley );
NSURL* tileUrl = [self tileURLForZoomLevel: zoomLevel tileX: tilex tileY: tiley];
NSData* tileData = [[ASIDownloadCache sharedCache] cachedResponseDataForURL: tileUrl];
UIGraphicsPushContext(context);
if ( tileData != nil )
{
UIImage* img = [UIImage imageWithData: tileData];
if ( img != nil )
{
[img drawInRect: [self rectForMapRect: mapRect] blendMode: kCGBlendModeNormal alpha: 1.0 ];
}
else
{
NSLog( @"oops - no image" );
}
CGSize s = CGContextConvertSizeToUserSpace( context, CGSizeMake( 40, 1 ));
UIFont* f = [UIFont systemFontOfSize: s.width];
[[UIColor blackColor] setFill];
[[NSString stringWithFormat: @"%d,%d", tilex, tiley] drawInRect: [self rectForMapRect: mapRect] withFont: f];
}
UIGraphicsPopContext();
}
- (void) requestFinished: (ASIHTTPRequest *) tileRequest
{
NSValue* mapRectValue = [tileRequest.userInfo objectForKey: @"mapRect"];
MKMapRect mapRect; [mapRectValue getValue: &mapRect];
NSValue *zoomScaleValue = [tileRequest.userInfo objectForKey:@"zoomScale"];
MKZoomScale zoomScale; [zoomScaleValue getValue: &zoomScale];
NSLog( @"requestFinished: %d, %d, %lf",
[[tileRequest.userInfo objectForKey:@"tilex"] intValue],
[[tileRequest.userInfo objectForKey:@"tiley"] intValue],
zoomScale );
[self setNeedsDisplayInMapRect: mapRect zoomScale: zoomScale];
}
Run Code Online (Sandbox Code Playgroud)
编辑: 我猜这可能是问题所在.
我遇到了与此处描述的问题非常相似的问题。就我而言,我无法重现所需的行为(http://developer.apple.com/library/ios/documentation/MapKit/Reference/MKOverlayView_class/Reference/Reference.html#//apple_ref/occ/instm/中描述MKOverlayView/setNeedsDisplayInMapRect:zoomScale :) 即使有最简单的代码:
- (BOOL)canDrawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale {
NSLog(@"This should trace forever");
[self setNeedsDisplayInMapRect:mapRect zoomScale:zoomScale];
return NO;
}
Run Code Online (Sandbox Code Playgroud)
或者更接近我的原始代码:
- (BOOL)canDrawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale {
NSLog(@"This should trace forever");
[SomeAsynchronousRequestWithCompletionHandler:^{
[self setNeedsDisplayInMapRect:mapRect zoomScale:zoomScale];
}];
return NO;
}
Run Code Online (Sandbox Code Playgroud)
在这两种情况下,setNeedsDisplayInMapRect:zoomScale:从未被调用过一次。
当我开始在dispatch_async中运行setNeedsDisplayInMapRect:zoomScale:时,情况发生了变化,该dispatch_async调度到canDrawMapRect运行的同一队列,例如:
- (BOOL)canDrawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale {
dispatch_queue_t queue = dispatch_get_current_queue();
NSLog(@"This should trace forever");
dispatch_async(queue, ^{
[self setNeedsDisplayInMapRect:mapRect zoomScale:zoomScale];
});
return NO;
}
Run Code Online (Sandbox Code Playgroud)
或包含异步作业:
- (BOOL)canDrawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale {
NSLog(@"This should trace forever");
dispatch_queue_t queue = dispatch_get_current_queue();
[SomeAsynchronousRequestWithCompletionHandler:^{
dispatch_async(queue, ^{
[self setNeedsDisplayInMapRect:mapRect zoomScale:zoomScale];
});
}];
return NO;
}
Run Code Online (Sandbox Code Playgroud)
使用dispatch_async - 我可以看到“这应该永远跟踪”字符串被无限地跟踪。我原来的问题也完全消失了。
稍后更新:目前,我使用dispatch_get_main_queue()来调用setNeedsDisplayInMapRect:zoomScale:像
- (BOOL)canDrawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale {
NSLog(@"This should trace forever");
[SomeAsynchronousRequestWithCompletionHandler:^{
dispatch_async(dispatch_get_main_queue(), ^{
[self setNeedsDisplayInMapRect:mapRect zoomScale:zoomScale];
});
}];
return NO;
}
Run Code Online (Sandbox Code Playgroud)