正确使用MKOverlayView

时间:2010-11-13 23:48:23

标签: iphone mapkit mkmapview overlay cgimage

我正在编写一个iPhone应用程序,我使用MKOverlayView在MKMapView上放置一个大的PNG图像(1936×2967)。我对如何在MKOverlayView中正确实现drawMapRect:函数感到有点困惑 - 我应该在绘制之前手动分割我的图像吗?或者我应该让MKOverlayView的机制处理所有这些?

我对其他帖子的印象是,在MKOverlayView可用之前,您需要自己为此类任务细分图像,并使用CATiledLayer。我想也许MKOverlayView会处理所有肮脏的工作。

我问的真正原因是因为当我使用分配工具通过Instruments运行我的应用程序时,我发现我的应用程序使用的实时字节数随着在地图上引入自定义图像而稳步增加。现在我没有分割我的图像,但我也看不到仪器泄漏工具中的内存泄漏记录。这是我的drawMapRect:function:

- (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context{
    // Load image from applicaiton bundle
    NSString* imageFileName = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"map.png"];
    CGDataProviderRef provider = CGDataProviderCreateWithFilename([imageFileName UTF8String]);
    CGImageRef image = CGImageCreateWithPNGDataProvider(provider, NULL, true, kCGRenderingIntentDefault);
    CGDataProviderRelease(provider);

    MKMapRect overlayMapRect = [self.overlay boundingMapRect];
    CGRect overlayRect = [self rectForMapRect:overlayMapRect];

    // draw image
    CGContextSaveGState(context);
    CGContextDrawImage(context, overlayRect, image);
    CGContextRestoreGState(context);

    CGImageRelease(image);

}

如果我的drawMapRect:函数不是这些内存问题的原因,那么有人知道它可能是什么吗?我知道通过调试我的viewForOverlay:mapView的函数只能为每个叠加调用一次,所以不是内存泄漏或其他东西。

欢迎任何建议!

谢谢,-Matt

编辑:所以事实证明,内存问题实际上是由MKMapView引起的 - 每次我移动地图时,所有内存使用量都会非常稳定上升并且永远不会降低 - 这似乎不太好:(

2 个答案:

答案 0 :(得分:1)

答案有点晚,如果将来有人遇到同样的问题,就把它留在这里。这里的缺陷是试图在文档明确说明的情况下渲染整个图像-

  

此外,应避免在每次调用此方法时绘制覆盖图的全部内容。相反,请始终考虑mapRect参数,并避免在该矩形之外绘制内容。

因此,您只需要在mapRect定义的区域中绘制图像的一部分

已更新:请记住,此处的drawRect可以大于mapRect,需要相应地调整绘制并剪切区域

let overlayMapRect = overlay.boundingMapRect
let overlayDrawRect = self.rect(for: overlayMapRect)

// watch out for draw rect adjustment here --
let drawRect = self.rect(for: mapRect).intersection(overlayDrawRect)
let scaleX = CGFloat(image.width) / overlayRect.width
let scaleY = CGFloat(image.height) / overlayRect.height
let transform = CGAffineTransform.init(scaleX: scaleX, y: scaleY)
let imageCut = drawRect.applying(transform)

// omitting optionals checks, you should not
let cutImage = image.cropping(to: imageCut)

// the usual vertical flip issue with image.draw
context.translateBy(x: 0, y: drawRect.maxY + drawRect.origin.y)
context.scaleBy(x: 1, y: -1)
context.draw(image, in: drawRect, byTiling: false)

答案 1 :(得分:0)

这是基于epolyakov答案的objc版本。它很好用,但没有任何旋转。

import random
bob_sayings = { 1: "I wish I was where I was when I wished I was here", 2:"There's a fine line between fishing and standing on the shore like an idiot.", 3: "After accomplishing a goal just look around to see whether you lost something or someone"}

bob_sayings

bob_sayings[random.randint(1, 3)]

如果您还需要管理图像的旋转,我发现了一个使用原始图像旋转版本的技巧(这是因为地图渲染总是绘制垂直矩形,并且使用此方法旋转图像会对其进行裁剪)。 因此,使用原始图像的旋转版本可以按照地图的期望使用垂直矩形进行渲染

- (void) drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context
{
    CGImageRef overlayImage = <your_uiimage>.CGImage;

    CGRect overlayRect = [self rectForMapRect:[self.overlay boundingMapRect]];
    CGRect drawRect = [self rectForMapRect:mapRect];

    CGRect rectPortion = CGRectIntersection(overlayRect, drawRect);
    CGFloat scaleX = rotatedImage.size.width / overlayRect.size.width;
    CGFloat scaleY = rotatedImage.size.height / overlayRect.size.height;
    CGAffineTransform transform = CGAffineTransformMakeScale(scaleX, scaleY);
    CGRect imagePortion = CGRectApplyAffineTransform(rectPortion, transform);

    CGImageRef cutImage = CGImageCreateWithImageInRect(overlayImage, imagePortion);

    CGRect finalRect = rectPortion;

    CGContextTranslateCTM(context, 0, finalRect.origin.y + CGRectGetMaxY(finalRect));
    CGContextScaleCTM(context, 1.0, -1.0);

    CGContextSetAlpha(context, self.alpha);
    CGContextDrawImage(context, finalRect, cutImage);
}

这是在边界矩形中生成旋转图像的方法

    UIImage* rotatedImage = [self rotatedImage:<your_uiimage> withAngle:<angle_of_image>];

    CGImageRef overlayImage = rotatedImage.CGImage;