setNeedsDisplayInMapRect不会触发新的drawMapRect:call
我正在使用自定义的MKOverlay/MKOverlayView
来完全覆盖Google自己的MKOverlay/MKOverlayView
,这些MKOverlay/MKOverlayView
是asynchronous加载的。 当我收到一个canDrawMapRect:zoomScale:
调用我的覆盖视图(并在这种情况下返回FALSE),然后调用setNeedsDisplayInMapRect:zoomScale:
一旦该图块可用时,我遵循请求卸载的图块的模式。
这一切通常工作,似乎在模拟器中完美的工作。
但是,在设备上,我有时会在覆盖层上find一个“洞” – 一个缺失的瓷砖。
我可以看到该图块被请求,并且请求完成。 我可以看到我调用了setNeedsDisplayInMapRect:zoomScale:
MKMapRect
并且传递了MKZoomScale
中提供的原始MKMapRect
和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]; }
编辑 : 我猜这可能是这个问题。
我有一个和这里描述的非常相似的问题。 在我的情况下,我无法重现所需的行为(在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]; }); }