MKMapView with multiple overlays memory-issue

后端 未结 2 898
青春惊慌失措
青春惊慌失措 2020-12-29 15:22

There seems to be an \"issue\" with overlays and the MapKit. Unlike annotations, overlays aren\'t reused and therefore when adding multiple overlays would cause

2条回答
  •  爱一瞬间的悲伤
    2020-12-29 16:18

    A Swift 4 version of the Objective-C code posted by @wkberg:

    MultiPolygon.swift:

    import MapKit
    
    /// A concatenation of multiple polygons to allow a single overlay to be drawn in the map,
    /// which will consume less resources
    class MultiPolygon: NSObject, MKOverlay {
        var polygons: [MKPolygon]?
    
        var boundingMapRect: MKMapRect
    
        init(polygons: [MKPolygon]?) {
            self.polygons = polygons
            self.boundingMapRect = MKMapRect.null
    
            super.init()
    
            guard let pols = polygons else { return }
            for (index, polygon) in pols.enumerated() {
                if index == 0 { self.boundingMapRect = polygon.boundingMapRect; continue }
                boundingMapRect = boundingMapRect.union(polygon.boundingMapRect)
            }
        }
    
        var coordinate: CLLocationCoordinate2D {
            return MKMapPoint(x: boundingMapRect.midX, y: boundingMapRect.maxY).coordinate
        }
    }
    

    MultiPolygonPathRenderer.swift:

    import MapKit
    
    /// A MKOverlayPathRenderer that can draw a concatenation of multiple polygons as a single polygon
    /// This will consume less resources
    class MultiPolygonPathRenderer: MKOverlayPathRenderer {
        /**
         Returns a `CGPath` equivalent to this polygon in given renderer.
    
         - parameter polygon: MKPolygon defining coordinates that will be drawn.
    
         - returns: Path equivalent to this polygon in given renderer.
         */
        func polyPath(for polygon: MKPolygon?) -> CGPath? {
            guard let polygon = polygon else { return nil }
            let points = polygon.points()
    
            if polygon.pointCount < 3 { return nil }
            let pointCount = polygon.pointCount
    
            let path = CGMutablePath()
    
            if let interiorPolygons = polygon.interiorPolygons {
                for interiorPolygon in interiorPolygons {
                    guard let interiorPath = polyPath(for: interiorPolygon) else { continue }
                    path.addPath(interiorPath, transform: .identity)
                }
            }
    
            let startPoint = point(for: points[0])
            path.move(to: CGPoint(x: startPoint.x, y: startPoint.y), transform: .identity)
    
            for i in 1..

    Usage - Adding the overlay to your MKMapView:

    // Add the overlay to mapView
    let polygonsArray: [MKPolygon] = self.buildMKPolygons()
    let multiPolygons = MultiPolygon.init(polygons: polygonsArray)
    self.mapView.addOverlay(multiPolygons)
    

    Usage - Implementing the viewForOverlay in your MKMapViewDelegate:

    // Method viewForOverlay:
    func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
        if overlay is MultiPolygon {
            let polygonRenderer = MultiPolygonPathRenderer(overlay: overlay)
            polygonRenderer.lineWidth = 0.5
            polygonRenderer.strokeColor = .mainGreen
            polygonRenderer.miterLimit = 2.0
            polygonRenderer.fillColor = UIColor.mainGreen.withAlphaComponent(0.2)
            return polygonRenderer
        }
    
        return MKOverlayRenderer()
    }
    

提交回复
热议问题