I have this function:
- (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context
{
TileOverlay *tileOverlay = (TileOverlay *)self.overlay;
NSArray *tilesInRect = [tileOverlay tilesInMapRect:mapRect zoomScale:zoomScale];
CGContextSetAlpha(context, tileAlpha);
for (ImageTile *tile in tilesInRect)
{
__block UIImage * image;
CGRect rect = [self rectForMapRect:tile.frame];
NSString *path = [[NSString alloc] initWithFormat:@".../%@.png", tile.imagePath];
NSLog(@"Loading tile from URL %@", path);
image =[UIImage imageWithData: [NSData dataWithContentsOfURL:[NSURL URLWithString: path]]];
CGContextSaveGState(context);
CGContextTranslateCTM(context, CGRectGetMinX(rect), CGRectGetMinY(rect));
CGContextScaleCTM(context, 1/zoomScale, 1/zoomScale);
CGContextTranslateCTM(context, 0, image.size.height);
CGContextScaleCTM(context, 1, -1);
CGContextDrawImage(context, CGRectMake(0, 0, image.size.width, image.size.height), [image CGImage]);
CGContextRestoreGState(context);
}
}
As you know dataWithContentsOfURL blocking thread until in will be done. I want to add image loading block to the GCD section.
I tried to do it like this:
- (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context
{
TileOverlay *tileOverlay = (TileOverlay *)self.overlay;
NSArray *tilesInRect = [tileOverlay tilesInMapRect:mapRect zoomScale:zoomScale];
CGContextSetAlpha(context, tileAlpha);
for (ImageTile *tile in tilesInRect)
{
__block UIImage * image;
CGRect rect = [self rectForMapRect:tile.frame];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW,0), ^{
NSString *path = [[NSString alloc] initWithFormat:@".../%@.png", tile.imagePath];
NSLog(@"Loading tile from URL %@", path);
image =[UIImage imageWithData: [NSData dataWithContentsOfURL:[NSURL URLWithString: path]]];
CGContextSaveGState(context);
CGContextTranslateCTM(context, CGRectGetMinX(rect), CGRectGetMinY(rect));
CGContextScaleCTM(context, 1/zoomScale, 1/zoomScale);
CGContextTranslateCTM(context, 0, image.size.height);
CGContextScaleCTM(context, 1, -1);
CGContextDrawImage(context, CGRectMake(0, 0, image.size.width, image.size.height), [image CGImage]);
CGContextRestoreGState(context);
});
}
}
But I got context error. Please help me with this stuff. How to use context operations in GCD block?
My first note is that MKOverlayView is depreciated. You should consider switching to MKOverlayRenderer.
There is no situation where you should use GCD from within a -draw__ method. That includes MKOverlayView -drawMapRect:zoomScale:inContext: as well UIView -drawRect:. Instead, you should be using an NSOperationQueue, in conjunction with -canDrawMapRect:zoomScale:zoomScale and setNeedsDisplayInMapRect:.
Here's some sudo-code for it:
- (BOOL)canDrawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale
{
BOOL hasAtLeastOneTile = NO;
TileOverlay *tileOverlay = (TileOverlay *)self.overlay;
NSArray *tilesInRect = [tileOverlay tilesInMapRect:mapRect zoomScale:zoomScale];
for (ImageTile *tile in tilesInRect) {
if ([tile isAvailable]) {
hasAtLeastOneTile = hasAtLeastOneTile || YES;
} else {
// Add operation to NSOperationQueue to fetch tile
__weak MKOverlayView *weakOverlay = self; // Weak ref to prevent retain cycles
NSOperation *op = [NSBlockOperation blockOperationWithBlock: ^{
//TODO: Load Tile
[weakOverlay setNeedsDisplayInMapRect:mapRect];
}];
[self.operationQueue addOperation:op];
}
}
return hasAtLeastOneTile;
}
Then in your -drawMapRect:zoomScale:inContext: you draw what tiles you have available and skip the ones that are not.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With