setNeedsDisplayInMapRect不会触发新的drawMapRect:call

我正在使用自定义的MKOverlay/MKOverlayView来完全覆盖Google自己的MKOverlay/MKOverlayView ,这些MKOverlay/MKOverlayView是asynchronous加载的。 当我收到一个canDrawMapRect:zoomScale:调用我的覆盖视图(并在这种情况下返回FALSE),然后调用setNeedsDisplayInMapRect:zoomScale:一旦该图块可用时,我遵循请求卸载的图块的模式。

这一切通常工作,似乎在模拟器中完美的工作。

但是,在设备上,我有时会在覆盖层上find一个“洞” – 一个缺失的瓷砖。

我可以看到该图块被请求,并且请求完成。 我可以看到我调用了setNeedsDisplayInMapRect:zoomScale: MKMapRect并且传递了MKZoomScale中提供的原始MKMapRectcanDrawMapRect: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]; } 

编辑 : 我猜这可能是这个问题。

我有一个和这里描述的非常相似的问题。 在我的情况下,我无法重现所需的行为(在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; } 

或者更接近我的原始代码:

 - (BOOL)canDrawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale { NSLog(@"This should trace forever"); [SomeAsynchronousRequestWithCompletionHandler:^{ [self setNeedsDisplayInMapRect:mapRect zoomScale:zoomScale]; }]; return NO; } 

在这两种情况下, setNeedsDisplayInMapRect:zoomScale:从来没有被调用过一次。

情况改变了,当我开始运行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; } 

或者包含asynchronous作业:

 - (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; } 

使用dispatch_async – 我可以看到“这应该跟踪永远”string被无休止地追查。 我原来的问题也完全消失了。

后来更新:目前,我使用dispatch_get_main_queue()来调用setNeedsDisplayInMapRect:zoomScale: like

 - (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; } 

上面的答案对我不起作用。 从我使用的NSLog打印输出中,我可以看到,尽pipe在canDrawMapRect中抓取了dispatch_get_current_queue()并将其存储以供以后使用,但仍然使用了不同的线程。 至less在iPad 4.3 Simulator中是这样,我没有尝试在设备上。

我的解决scheme是不太令人满意的,更容易出错的解决scheme,等待x时间才打电

 -(void)setNeedsDisplay:(WebRequest*)webRequest { [webRequest retain]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.25 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ [webRequest autorelease]; [delegate setNeedsDisplayInMapRect:webRequest.request.requestedMapRect zoomScale:webRequest.request.requestedScale]; }); }