Message from debugger: Terminated due to memory issue

前端 未结 6 1618
小蘑菇
小蘑菇 2021-02-18 21:52

My app working with Geojson file. I use MapBox SDK to add MGLPolyline to map. But the problem is my file too large, so that the app crash and got the e

6条回答
  •  青春惊慌失措
    2021-02-18 22:28

    The problem here is related to effective memory management. You are loading a lot of data via your json file. You realized that you needed to do the majority of the work on a background queue (thread) however the issue is how you are updating the UI via DispatchQueue.main.async function. In the current version of the drawPolyline() method you are switching between the background queue and the main queue 66234 times, given the number of objects in your first loop. Also you were creating the same number of CLLocationCoordinate2D arrays.

    This leads to a huge memory footprint. You do not mention any requirements in regards to how you render the lines. So if we restructure your drawPolyline() method to use a instance variable for the CLLocationCoordinate2D array so we only use one and then we process all of the json file before we update the UI. The memory usage dropped down to a some what more manageable 664.6 MB.

    Of course the rendering may not be exactly what you are looking for and if that's the case you might want to restructure your CLLocationCoordinate2D array into a more suitable data structure.

    Below is your ViewController class with the rewritten drawPolyline() as drawPolyline2()

    import UIKit
    import Mapbox
    
    class ViewController: UIViewController, MGLMapViewDelegate {
    
    @IBOutlet var mapboxView: MGLMapView!
    
    
    fileprivate var coordinates = [[CLLocationCoordinate2D]]()
    fileprivate var jsonData: NSData?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        mapboxView = MGLMapView(frame: view.bounds)
        mapboxView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    
        // mapboxView.setCenter(CLLocationCoordinate2D(latitude: 45.5076, longitude: -122.6736),
        //                             zoomLevel: 11, animated: false)
    
        mapboxView.setCenter(CLLocationCoordinate2D(latitude: 1.290270, longitude: 103.851959),
                             zoomLevel: 11, animated: false)
    
    
        view.addSubview(self.mapboxView)
    
    
        mapboxView.delegate = self
        mapboxView.allowsZooming = true
    
        drawPolyline2()
        //newWay()
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    
    
    func drawPolyline2() {
    
        DispatchQueue.global(qos: .background).async {
    
            if let path = Bundle.main.path(forResource: "KMLMAPNew", ofType: "json") {
                let fileURL = URL(fileURLWithPath: path)
                if let data = try? Data(contentsOf: fileURL) {
    
                    do {
    
                        let dictionary = try JSONSerialization.jsonObject(with: data as Data, options: []) as? Dictionary
    
                        if let features = dictionary?["features"] as? Array {
    
                            print("** START **")
    
                            for feature in features {
                                guard let feature = feature as? Dictionary, let geometry = feature["geometry"] as? Dictionary else { continue }
    
                                if geometry["type"] as? String == "LineString" {
                                    // Create an array to hold the formatted coordinates for our line
    
                                    if let locations = geometry["coordinates"] as? Array {
                                        // Iterate over line coordinates, stored in GeoJSON as many lng, lat arrays
    
                                        var featureCoordinates = [CLLocationCoordinate2D]()
    
                                        for location in locations {
                                            // Make a CLLocationCoordinate2D with the lat, lng
                                            if let location = location as? Array{
                                                let coordinate = CLLocationCoordinate2DMake(location[1].doubleValue, location[0].doubleValue)
    
                                                // Add coordinate to coordinates array
                                                featureCoordinates.append(coordinate)
                                            }
                                        }
    
                                        // Uncomment if you need to store for later use.
                                        //self.coordinates.append(featureCoordinates)
    
                                        DispatchQueue.main.async {
                                            let line = MGLPolyline(coordinates: &featureCoordinates, count: UInt(featureCoordinates.count))
    
                                            // Optionally set the title of the polyline, which can be used for:
                                            //  - Callout view
                                            //  - Object identification
                                            line.title = "Crema to Council Crest"
                                            self.mapboxView.addAnnotation(line)
    
                                        }
    
    
                                    }
    
                                }
    
                            }
    
                            print("** FINISH **")
    
                        }
    
                    } catch {
                        print("GeoJSON parsing failed")
                    }
                }
            }
        }
    }
    
    
    func drawSmallListObj(list: [Dictionary]){
        for obj in list{
            //            print(obj)
            if let feature = obj as? Dictionary {
                if let geometry = feature["geometry"] as? Dictionary {
                    if geometry["type"] as? String == "LineString" {
                        // Create an array to hold the formatted coordinates for our line
                        var coordinates: [CLLocationCoordinate2D] = []
    
                        if let locations = geometry["coordinates"] as? Array {
                            // Iterate over line coordinates, stored in GeoJSON as many lng, lat arrays
                            for location in locations {
                                // Make a CLLocationCoordinate2D with the lat, lng
                                if let location = location as? Array{
                                    let coordinate = CLLocationCoordinate2DMake(location[1].doubleValue, location[0].doubleValue)
    
                                    // Add coordinate to coordinates array
                                    coordinates.append(coordinate)
                                }
                            }
                        }
    
                        let line = MGLPolyline(coordinates: &coordinates, count: UInt(coordinates.count))
    
                        // Optionally set the title of the polyline, which can be used for:
                        //  - Callout view
                        //  - Object identification
                        line.title = "Crema to Council Crest"
    
                        // Add the annotation on the main thread
                        DispatchQueue.main.async {
                            // Unowned reference to self to prevent retain cycle
                            [unowned self] in
                            self.mapboxView.addAnnotation(line)
                        }
                    }
                }
            }
        }
    }
    func mapView(_ mapView: MGLMapView, alphaForShapeAnnotation annotation: MGLShape) -> CGFloat {
        // Set the alpha for all shape annotations to 1 (full opacity)
        return 1
    }
    
    func mapView(_ mapView: MGLMapView, lineWidthForPolylineAnnotation annotation: MGLPolyline) -> CGFloat {
        // Set the line width for polyline annotations
        return 2.0
    }
    
    func mapView(_ mapView: MGLMapView, strokeColorForShapeAnnotation annotation: MGLShape) -> UIColor {
        // Give our polyline a unique color by checking for its `title` property
        if (annotation.title == "Crema to Council Crest" && annotation is MGLPolyline) {
            // Mapbox cyan
            return UIColor(red: 59/255, green:178/255, blue:208/255, alpha:1)
        }
        else
        {
            return UIColor.red
        }
    }
    
    
    }
    

提交回复
热议问题