2012-04-12 20 views
8

पर कॉल करें मैं अपने स्वयं के टाइल्स के साथ Google बेसमैप को पूरी तरह से कवर करने के लिए कस्टम MKOverlay/MKOverlayView का उपयोग कर रहा हूं, जो असीमित रूप से लोड होते हैं। मैं अनलोडेड टाइल्स का अनुरोध करने के पैटर्न का पालन करता हूं जब मुझे canDrawMapRect:zoomScale: मेरे ओवरले व्यू (और उस मामले में FALSE लौटाते हुए) पर कॉल प्राप्त होता है, फिर टाइल उपलब्ध होने के बाद setNeedsDisplayInMapRect:zoomScale: पर कॉल किया जाता है।setNeedsDisplayInMapRect नया drawMapRect ट्रिगर नहीं करता है:

यह सब आम तौर पर काम करता है, और सिम्युलेटर में पूरी तरह से काम करता प्रतीत होता है।

हालांकि, डिवाइस पर मुझे कभी-कभी ओवरले में 'छेद' मिलता है - एक लापता टाइल।

मैं देख सकता हूं कि टाइल का अनुरोध किया गया है, और अनुरोध पूरा हो गया है। मैं देख सकता हूं कि मैं 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]; 
} 

संपादित: I'm guessing that this is likely the issue.

+0

हाय, क्या आपको कोई समाधान मिला? मुझे एक ही समस्या है :( – Igor

+0

इस मुद्दे पर +1। –

+0

क्या आपको लोगों को कोई समाधान मिला? –

उत्तर

1

मैं बहुत यहाँ वर्णित एक करने के लिए इसी तरह की एक समस्या हुई।

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

दोनों ही मामलों मेरे मामले में मैं वांछित व्यवहार (http://developer.apple.com/library/ios/documentation/MapKit/Reference/MKOverlayView_class/Reference/Reference.html#//apple_ref/occ/instm/MKOverlayView/setNeedsDisplayInMapRect:zoomScale में :) यहां तक ​​कि सबसे सरल कोड होने संभव वर्णित पुन: पेश नहीं कर सका setNeedsDisplayInMapRect: ज़ूमस्केले: को कभी भी एक बार भी नहीं बुलाया गया है।

स्थिति, बदल गया जब मैं 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; 
} 

या अतुल्यकालिक काम के साथ शामिल:

- (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 का उपयोग करना - मैं देख सकता हूं "यह हमेशा के लिए पता लगाना चाहिए" स्ट्रिंग अंतहीन रूप से पता लगाया जा रहा है। मेरी मूल समस्या पूरी तरह से गायब हो गई है।

बाद में अपलोड करें: वर्तमान में, मैं 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; 
} 
+0

मैंने इसे स्वयं नहीं किया है (समस्या अब मेरे लिए प्रासंगिक नहीं है) लेकिन आप समाधान अच्छा दिखता है। अच्छा काम! – TomSwift

+0

भले ही यह दृष्टिकोण काम करता है, फिर भी यह एक ऐप्पल बग होगा। आप किसी भी थ्रेड से सेटNeedsDisplayInMapRect को कॉल करने में सक्षम होना चाहिए, न केवल ड्राइंग थ्रेड। आखिरकार, आप इसे मुख्य धागे से बुलाएंगे। मैं नक्शा इंटरफ़ेस के लिए झुकाव नहीं कर सकता, लेकिन मैंने सामान्य कैटिल्डलेयर पर आपके दृष्टिकोण का परीक्षण किया, और यह विश्वसनीय रूप से काम नहीं करता था। देखें http://stackoverflow.com/a/13095551/908621 – fishinear

+0

यह थ्रेड नहीं है जिसे आप setNeedsDisplayInMapRect को कॉल करने के लिए उपयोग करते हैं, यह समस्या है, समस्या यह है कि अगर सेटएड्सडिस्प्लेइन मैपरेक्ट को कॉल किया जाता है, जबकि ओवरले को प्रस्तुत किया जा रहा है तो कॉल को अनदेखा किया जाता है। मुख्य समस्या पर setNeedsDisplayInMapRect को कॉल करके यह समस्या हल नहीं होती है। – loomer

0

जवाब ऊपर मेरे लिए काम नहीं किया। मैंने उपयोग किए गए एनएसएलओजी प्रिंटआउट से मैं देख सकता था कि canDrawMapRect में dispatch_get_current_queue() को पकड़ने और इसे बाद में उपयोग के लिए संग्रहीत करने के बावजूद एक अलग थ्रेड का उपयोग किया जा रहा था। आईपैड 4.3 सिम्युलेटर में यह मामला कम से कम था, मैंने डिवाइस पर प्रयास नहीं किया था।

मेरा समाधान कम संतोषजनक था और कॉल करने से पहले प्रतीक्षा समय के अधिक त्रुटि प्रवण समाधान था।

-(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]; 
    });  
} 
+0

कृपया, देखें: मैंने अपना जवाब अपडेट किया है ("अद्यतन अद्यतन" शब्दों से) - मैं dispatch_get_main_queue() का भी उपयोग करता हूं और मुझे अतिरिक्त प्रेषण की आवश्यकता नहीं है। क्या आप वाकई इस देरी की ज़रूरत है? –

+0

मेरे मामले में देरी की आवश्यकता थी। मैंने इसे शुरू करने के बाद dispatch_after के बिना कोशिश की। – deathbytes