iosswiftcore-graphicsapple-maps

Weird behaviour touch ended called automatically


I am rendering the current screen (map screen) into a smaller view with magnifying effect.

Problem illustration

My app taking 110 MB memory. As soon as I start dragging the annotation, memory reaches to 130-140 MB then touchesEnded is called forcefully by system.

Expected behaviour

App should not call touchesEnded automatically.

What I did in dragging of annotation is added a magnified view into smaller view. Below is my code of draw method.

public override func draw(_ rect: CGRect) {
    UIGraphicsBeginImageContextWithOptions(self.magnifiedView!.bounds.size, false, 0.0);
    guard let context = UIGraphicsGetCurrentContext() else { return }
    
    context.translateBy(x: radius, y: radius)
    context.scaleBy(x: scale, y: scale)
    context.translateBy(x: -magnifiedPoint.x, y: -magnifiedPoint.y)
    
    removeFromSuperview()
    self.subviews.first?.removeFromSuperview()
    magnifiedView?.layer.render(in: context)
    let mapImage = UIGraphicsGetImageFromCurrentImageContext();
    self.addSubview(UIImageView(image: mapImage))
    magnifiedView?.addSubview(self)
    UIGraphicsEndImageContext();
}

As soon as the user starts dragging the annotation I started calling setNeedDisplay which triggers the draw method again and again. I don't know what to do now. I am totally stuck at this point.


Solution

  • The biggest issue you have is that you shouldn't be overriding draw at all. All this code does is update an image view's image property. draw is not the correct place for this. draw should only be used to actually draw content into self. It shouldn't be used to update subviews. It shouldn't add or remove views. It definitely shouldn't be used to remove self from the view hierarchy.

    Certainly the call to removeFromSuperview() is not helping. That is likely why the drag is being cancelled. You need to leave the view in place.

    Leave the image view in place. Leave this view in place. Generate the new image and update the image view's image property with the new image. Don't remove any views. Don't add any views during that process.

    Put the code to generate and update the new image into a function that you can call as the drag operation moves around. This could be in the handler for a pan gesture recognizer if that's what you are using. Or it could be in touchesMoved(with:) if you are overriding the various touches... methods.