我正在使用NSXMLParser解析大型kml文件(18 MB)并同时存储核心数据中每个位置的坐标,我观察到的是在解析文件内存堆积的3/4并且应用程序崩溃后内存未被释放,我已经尝试了stackoverflow上给出的大部分答案,但没有用。任何帮助都受到欢迎。
var currentElement : String = ""
var place:Place?
var polygon:Polygon?
var placeName = ""
var shouldAddCoordinates = false
private lazy var privateManagedObjectContext: NSManagedObjectContext = {
var managedObjectContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = (UIApplication.shared.delegate as! AppDelegate).managedObjectContext.persistentStoreCoordinator
return managedObjectContext
}()
override init() {
super.init()
}
// Xml Parser delegate methods
func parserDidStartDocument(_ parser: XMLParser) {
print("..Xml parsing has started")
}
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
currentElement = elementName
if elementName == "Placemark" {
place = NSEntityDescription.insertNewObject(forEntityName: "Place", into: privateManagedObjectContext) as? Place
place?.placeName = ""
}
if elementName == "Polygon" {
polygon = NSEntityDescription.insertNewObject(forEntityName: "Polygon", into: privateManagedObjectContext) as? Polygon
let fetchRequest = NSFetchRequest<Place>(entityName: "Place")
fetchRequest.predicate = NSPredicate(format: "placeName == %@", placeName)
do{
let fetchResult = try privateManagedObjectContext.fetch(fetchRequest) as [Place]
polygon?.place = place
polygon?.placeName = placeName
shouldAddCoordinates = fetchResult.first?.placeName == placeName ? true:false
}
catch{}
}
if elementName == "coordinates" {
let fetchRequest = NSFetchRequest<Place>(entityName: "Place")
fetchRequest.predicate = NSPredicate(format: "placeName == %@", placeName)
let fetchResult = try? privateManagedObjectContext.fetch(fetchRequest) as [Place]
shouldAddCoordinates = fetchResult?.first?.placeName == placeName ? true:false
}
if elementName == "name"{
placeName = ""
}
}
func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
currentElement = elementName
if elementName == "coordinates" {
let fetchRequest = NSFetchRequest<Place>(entityName: "Polygon")
let sortDescriptor = NSSortDescriptor(key: "polygonID", ascending: true )
fetchRequest.sortDescriptors = [sortDescriptor]
let fetchResult = try? privateManagedObjectContext.fetch(fetchRequest as! NSFetchRequest<NSFetchRequestResult>) as! [Polygon]
if fetchResult?.count == 0{
polygon?.polygonID = 1
}
else{
polygon?.polygonID = Int64(fetchResult!.count)
}
polygon?.place = place
}
if elementName == "coordinates" || elementName == "Polygon" || elementName == "name"{
if self.privateManagedObjectContext.hasChanges{
privateManagedObjectContext.performAndWait {
do{
try self.privateManagedObjectContext.save()
}
catch{}
}
}
}
else if elementName == "Placemark"{
placeName = ""
privateManagedObjectContext.performAndWait {
do{
try self.privateManagedObjectContext.save()
}
catch{}
}
privateManagedObjectContext.reset()
}
}
func parser(_ parser: XMLParser, foundCharacters string: String) {
if currentElement == "name" {
if string == "\n" {
return
}
place?.placeName? += string
placeName += string
}
if currentElement == "coordinates"{
if shouldAddCoordinates {
privateManagedObjectContext.performAndWait{
if string == "\n" {
return
}
else{
let coordinates = NSEntityDescription.insertNewObject(forEntityName: "Coordinates", into: self.privateManagedObjectContext) as! Coordinates
let longitude = (string.components(separatedBy: ",") as [NSString]).first!.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) as NSString
let latitude = (string.components(separatedBy: ",") as [NSString]).last!.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) as NSString
let latitudeDegrees : CLLocationDegrees = latitude.doubleValue
let longitudeDegrees: CLLocationDegrees = longitude.doubleValue
coordinates.latitude = latitudeDegrees as NSNumber?
coordinates.longitude = longitudeDegrees as NSNumber?
coordinates.coordinatesDate = Date() as NSDate
coordinates.polygon = self.polygon
print("\(String(describing: coordinates.polygon?.placeName!)) has coordinates \(coordinates.latitude!),\(coordinates.longitude!)")
}
}
}
}
}
func parserDidEndDocument(_ parser: XMLParser) {
print("..Parser has finished parsing..")
}
func getManagedObject() -> NSManagedObjectContext{
let managedObjectContext = (UIApplication.shared.delegate as! AppDelegate).managedObjectContext
return managedObjectContext
}
func saveCoordinates(){
let url = Bundle.main.url(forResource: "IND_adm1_1", withExtension: "kml")
let xmlParser = XMLParser(contentsOf: url!)
xmlParser?.delegate = self
_ = xmlParser?.parse()
}