Правильное использование MKOverlayView - PullRequest
2 голосов
/ 14 ноября 2010

Я пишу приложение для iPhone, в котором я помещаю большое изображение PNG (1936 × 2967) в MKMapView, используя MKOverlayView. Я немного озадачен тем, как правильно реализовать функцию drawMapRect: в MKOverlayView - нужно ли вручную сегментировать изображение перед его рисованием? Или я должен позволить механизмам MKOverlayView обрабатывать все это?

У меня сложилось впечатление, что до публикации MKOverlayView вы должны были самостоятельно сегментировать изображения для такого рода задач и использовать CATiledLayer. Я подумал, что, возможно, MKOverlayView позаботится обо всей грязной работе.

Реальная причина, по которой я спрашиваю, заключается в том, что, когда я запускаю свое приложение через Инструменты с помощью инструмента выделения, я обнаруживаю, что число живых байтов, которые использует мое приложение, постоянно увеличивается с появлением пользовательского изображения на карте. Сейчас я НЕ сегментирую свое изображение, но я также не вижу записей об утечках памяти в инструменте утечек в Инструментах. Вот мой drawMapRect: функция:

- (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 ]

1 голос
/ 31 июля 2018

Немного поздний ответ, оставив его здесь, если кто-то еще столкнется с той же проблемой в будущем.Недостатком здесь является попытка визуализировать целое изображение, в то время как документация ясно говорит -

Кроме того, вам следует избегать рисования всего содержимого наложения при каждом вызове этого метода.Вместо этого всегда принимайте во внимание параметр 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)
0 голосов
/ 20 августа 2018

Вот версия объекта, основанная на ответе Еполякова.Он отлично работает, но только без поворота.

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

И это метод, который создает повернутое изображение в ограничительном прямоугольнике

- (UIImage*) rotatedImage:(UIImage*)image withAngle:(CGFloat)angle
{
    float radians = degreesToRadians(angle);

    CGAffineTransform xfrm = CGAffineTransformMakeRotation(radians);
    CGRect imageRect = CGRectMake(0, 0, image.size.width, image.size.height);
    CGRect rotatedImageBoundingRect = CGRectApplyAffineTransform (imageRect, xfrm);


    UIGraphicsBeginImageContext(rotatedImageBoundingRect.size);
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    CGContextTranslateCTM (ctx, rotatedImageBoundingRect.size.width/2., rotatedImageBoundingRect.size.height/2.);
    CGContextScaleCTM(ctx, 1.0, -1.0);
    CGContextRotateCTM (ctx, radians);
    CGContextDrawImage (ctx, CGRectMake(-image.size.width / 2, -image.size.height / 2, image.size.width, image.size.height), image.CGImage);

    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return newImage;
}
...