ios – 来自调试器的消息:由于内存问题而终止

我的应用程序使用Geojson文件.我使用 MapBox SDK将MGLpolyline添加到地图中.但问题是我的文件太大,以至于应用程序崩溃并收到错误:来自调试器的消息:由于内存问题而终止.我在第一次循环时面对66234个对象.我试图将数组块化为新数组,但没有成功.请帮我解决问题.这是我在地图上绘制的代码,这里是我的 test project on github use Xcode 8.1如果有任何不同的第三方可以解决我的问题也欢迎:
func drawpolyline() {

    // Parsing GeoJSON can be cpu intensive,do it on a background thread
    dispatchQueue.global(qos: .background).async {
        // Get the path for example.geojson in the app's bundle
        let jsonPath = Bundle.main.path(forResource: "KMLMAPNew",ofType: "json")
        let jsonData = NSData(contentsOfFile: jsonPath!)

        do {
            // Load and serialize the GeoJSON into a dictionary filled with properly-typed objects
            guard let jsonDict = try JSONSerialization.jsonObject(with: jsonData! as Data,options: []) as? Dictionary<String,AnyObject>,let features = jsonDict["features"] as? Array<AnyObject> else{return}

            for feature in features {
                guard let feature = feature as? Dictionary<String,let geometry = feature["geometry"] as? Dictionary<String,AnyObject> else{ continue }

                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<AnyObject> {
                        // 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<AnyObject>{
                                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)
                    }
                }
            }
        }
        catch
        {
            print("GeoJSON parsing Failed")
        }
    }
}

编辑:: @ Alessandro Ornano和@fragilecat非常感谢.但这些解决方案仍然无法解决iPad终止应用的问题.我认为很难改变当前的代码以使其正常工作,因为数据太大了.我想我需要另一种适用于大数据的解决方案.就像将数组分块到小数组中一样,然后通过队列加载它们.但我不知道如何开始:(

我向MapBox支持团队发送电子邮件,询问建议.

解决方法

这里的问题与有效的内存管理有关.您正在通过json文件加载大量数据.您意识到您需要在后台队列(线程)上完成大部分工作,但问题是如何通过dispatchQueue.main.async函数更新UI.在当前版本的drawpolyline()方法中,在给定第一个循环中的对象数量的情况下,您将在后台队列和主队列之间切换66234次.您还创建了相同数量的CLLocationCoordinate2D数组.

这导致巨大的内存占用.您没有提到有关如何渲染线条的任何要求.因此,如果我们重新构建drawpolyline()方法以使用CLLocationCoordinate2D数组的实例变量,那么我们只使用一个,然后在更新UI之前处理所有json文件.内存使用量下降到更可管理的664.6 MB.

当然,渲染可能并不完全符合您的要求,如果是这种情况,您可能希望将CLLocationCoordinate2D数组重组为更合适的数据结构.

下面是您的ViewController类,其中重写的drawpolyline()为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,AnyObject>

                    if let features = dictionary?["features"] as? Array<AnyObject> {

                        print("** START **")

                        for feature in features {
                            guard let feature = feature as? Dictionary<String,AnyObject> 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<AnyObject> {
                                    // Iterate over line coordinates,lat arrays

                                    var featureCoordinates = [CLLocationCoordinate2D]()

                                    for location in locations {
                                        // Make a CLLocationCoordinate2D with the lat,lng
                                        if let location = location as? Array<AnyObject>{
                                            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<String,AnyObject>]){
    for obj in list{
        //            print(obj)
        if let feature = obj as? Dictionary<String,AnyObject> {
            if let geometry = feature["geometry"] as? Dictionary<String,AnyObject> {
                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<AnyObject> {
                        // Iterate over line coordinates,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
    }
}


}

相关文章

UITabBarController 是 iOS 中用于管理和显示选项卡界面的一...
UITableView的重用机制避免了频繁创建和销毁单元格的开销,使...
Objective-C中,类的实例变量(instance variables)和属性(...
从内存管理的角度来看,block可以作为方法的传入参数是因为b...
WKWebView 是 iOS 开发中用于显示网页内容的组件,它是在 iO...
OC中常用的多线程编程技术: 1. NSThread NSThread是Objecti...