Невозможно освободить распознаватель жестов из стека памяти - PullRequest
0 голосов
/ 04 декабря 2018

Я пытаюсь реализовать пользовательский распознаватель жестов на моем mapView, который не позволит пользователям увеличивать или уменьшать масштаб, превышающий определенный порог, установленный MKCoordinateSpan.

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

Поскольку я добавил пользовательский распознаватель жестов, память не освобождается при исчезновении представления.Чего мне не хватает, кроме удаления распознавателя жестов из mapView?

MapViewController:

class MapViewController: UIViewController, CLLocationManagerDelegate {

    @IBOutlet var mapView: MKMapView!

    override func viewDidLoad() {
        super.viewDidLoad()
        loadMapView()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        if mapView == nil {
            loadMapView()
        }
    }

    override func viewDidDisappear(_ animated:Bool) {
        super.viewDidDisappear(animated)
        self.applyMapViewMemoryFix()
    }

    func loadMapView() {
        self.edgesForExtendedLayout = []
        setMapView()
    }

    func setMapView() {
        if self.mapView == nil {
            addMapView()
        }

        mapView.delegate = self
        mapView.mapType = .mutedStandard
        mapView.autoresizingMask = [.flexibleWidth,.flexibleHeight]
    }

    func addMapView() {
        mapView = MKMapView()
        mapView.frame = self.navigationController!.view.bounds
        mapView.mapType = MKMapType.standard
        mapView.isZoomEnabled = true
        mapView.isScrollEnabled = true
        self.view.addSubview(mapView)
    }

    func applyMapViewMemoryFix() {
        for recognizer in (self.mapView?.gestureRecognizers)! {
            if recognizer is WildCardGestureRecognizer {
                self.mapView.removeGestureRecognizer(recognizer)
            }
        }

        self.mapView.showsUserLocation = false
        self.mapView.delegate = nil
        self.mapView.removeFromSuperview()
        self.mapView = nil
    }

}

Расширение, в котором я устанавливаю границы для распознавателя жестов:

extension MapViewController: MKMapViewDelegate {

    // View Region Changing
    func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
        let northernBorder = 32.741152
        let southernBorder = 32.731461
        let easternBorder = -117.143622
        let westernBorder = -117.157399

        var latitude  = mapView.region.center.latitude
        var longitude = mapView.region.center.longitude

        if (mapView.region.center.latitude > northernBorder) {
            latitude = northernBorder
        }

        if (mapView.region.center.latitude <  southernBorder) {
            latitude = southernBorder
        }

        if (mapView.region.center.longitude > easternBorder) {
            longitude = easternBorder
        }

        if (mapView.region.center.longitude < westernBorder) {
            longitude = westernBorder
        }

        let tapInterceptor = WildCardGestureRecognizer(target: nil, action: nil)

        tapInterceptor.touchesBeganCallback = {_, _ in
            mapView.isZoomEnabled = true
        }

        tapInterceptor.touchesMovedCallback = {_, _ in
            if tapInterceptor.scale < 1 {
                if (latitude != mapView.region.center.latitude || longitude != mapView.region.center.longitude)
                    || ((mapView.region.span.latitudeDelta > (northernBorder - southernBorder) )
                        || (mapView.region.span.longitudeDelta > (easternBorder - westernBorder))) {
                    let span = MKCoordinateSpan.init(latitudeDelta: 0.007, longitudeDelta: 0.007)
                    if mapView.region.span.latitudeDelta > span.latitudeDelta || mapView.region.span.longitudeDelta > span.longitudeDelta {
                        mapView.isZoomEnabled = false
                    } else {
                        mapView.isZoomEnabled = true
                    }
                }
            } else if tapInterceptor.scale > 1 {
                let minimumSpan = MKCoordinateSpan.init(latitudeDelta: 0.002, longitudeDelta: 0.002)
                if mapView.region.span.latitudeDelta < minimumSpan.latitudeDelta || mapView.region.span.longitudeDelta < minimumSpan.longitudeDelta {
                    mapView.isZoomEnabled = false
                } else {
                    mapView.isZoomEnabled = true
                }
            }
        }

        tapInterceptor.touchesEndedCallback = {_, _ in
            mapView.isZoomEnabled = true
        }

        mapView.addGestureRecognizer(tapInterceptor)
    }
}

Распознаватель пользовательских жестов:

class WildCardGestureRecognizer: UIPinchGestureRecognizer {

    var touchesBeganCallback: ((Set<UITouch>, UIEvent) -> Void)?
    var touchesMovedCallback: ((Set<UITouch>, UIEvent) -> Void)?
    var touchesEndedCallback: ((Set<UITouch>, UIEvent) -> Void)?

    override init(target: Any?, action: Selector?) {
        super.init(target: target, action: action)
        self.cancelsTouchesInView = false
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
        super.touchesBegan(touches, with: event)
        touchesBeganCallback?(touches, event)
    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
        super.touchesMoved(touches, with: event)
        touchesMovedCallback?(touches, event)
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent) {
        super.touchesEnded(touches, with: event)
        touchesEndedCallback?(touches, event)
    }

    override func canPrevent(_ preventedGestureRecognizer: UIGestureRecognizer) -> Bool {
        return false
    }

    override func canBePrevented(by preventingGestureRecognizer: UIGestureRecognizer) -> Bool {
        return false
    }
}

1 Ответ

0 голосов
/ 04 декабря 2018

Утечка памяти при объявлении здесь жеста

 let tapInterceptor = WildCardGestureRecognizer(target: nil, action: nil)
 .
 .
 .
 mapView.addGestureRecognizer(tapInterceptor)

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

var tapInterceptor:WildCardGestureRecognizer!

и добавьте init жеста и обратные вызовы внутри функции, затем вызовите его в форме viewDidLoad

Также удалите @IBOutle

@IBOutlet var mapView: MKMapView!

Если вы не сделаете это внутри раскадровки, также я не думаю, что способ удаления / добавления будет иметь значение, поскольку освобождение объектов в IOS всегда не освобождает всю принятую часть, поэтому лучше оставить отображение карты только с1 жест вместо накопления большой утечки из тех, которые вы потеряли, когда вы выбираете / снимаете отметку с этого крана

...