nsxmlparser ios8

Accidente NSXMLParser iOS8



(5)

Tuve un bloqueo en NSXMLParser

* Aplicación de finalización debido a la excepción no detectada ''NSInternalInconsistencyException'', razón: ''NSXMLParser no admite el análisis de reentrada.''

Aquí está mi código

NSString *wrappedSnippet = [NSString stringWithFormat:@"<html>%@</html>", self.snippet]; NSXMLParser *parser = [[NSXMLParser alloc] initWithData:[wrappedSnippet dataUsingEncoding:NSUTF8StringEncoding]]; [parser setDelegate:self]; [parser parse];

la aplicación se bloquea en la última línea.

Tenga en cuenta que todo funciona perfecto en iOS7.


iOS8 arroja una excepción que las versiones anteriores capturaron y manejaron en segundo plano.
ver manual As desde ios 5 ¡NSXMLParser es seguro para hilos, pero no reentrante! asegúrese de no llamar a análisis desde su delegado NSXMLParser. "Ser" en tu caso.


dispatch_queue_t reentrantAvoidanceQueue = dispatch_queue_create("reentrantAvoidanceQueue", DISPATCH_QUEUE_SERIAL); dispatch_async(reentrantAvoidanceQueue, ^{ NSXMLParser* parser = [[NSXMLParser alloc] initWithData:xml]; [parser setDelegate:self]; if (![parser parse]) { NSLog(@"There was an error=%@ parsing the xml. with data %@", [parser parserError], [[NSString alloc] initWithData:xml encoding: NSASCIIStringEncoding]); } [parser release]; }); dispatch_sync(reentrantAvoidanceQueue, ^{ });

Reemplace su código con las líneas anteriores, ¡espero que lo ayude!


¡Resolví mi problema enviando analizador en cola de fondo!

NSXMLParser ahora es threadsafe. Sin embargo, no es reentrante en un hilo dado; no invoque -parse en un NSXMLParser desde una devolución de llamada delegada de otro NSXMLParser.

- (void)parseWithCompletion:(ParserHandler)handler { dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul); dispatch_async(queue, ^{ self.handler = handler; [self parse]; }); } - (void)parserDidEndDocument:(NSXMLParser *)parser { dispatch_async(dispatch_get_main_queue(), ^{ if (self.handler) { self.handler(YES, self.dictionary, nil); self.handler = nil; } }); }


En este tema, eso significa que puede volver a llamar a la función [NSXMLParser analizar] en cualquier elemento de su delegado. A veces puede llamar a [análisis sintáctico] en parserDidEndDocument:
¡Pero le notificará que este es un error de reentrada!

Entonces, la solución es, o podrías [analizador sintáctico] en una cola diferente,
por ejemplo, puede hacerlo llamando a dispatch_async (dispatch_get_main_queue (), ^ {do en block});

o, necesita ajustar su flujo de llamadas,
asegúrese de no llamar a la función de análisis en delegado.


Tuve el mismo problema y escribí una subclase basada en NSXMLParser que maneja el caso:

class SynchronizedXMLParser: NSXMLParser { // shared queue private static let _serialQueue: NSOperationQueue = { let queue = NSOperationQueue() queue.qualityOfService = NSQualityOfService.UserInitiated // making it serial on purpose in order to avoid // the "reentrant parsing" issue queue.maxConcurrentOperationCount = 1 return queue }() // instance level convenience accessor private var _serialQueue: NSOperationQueue { get { return self.dynamicType._serialQueue } } private weak var _associatedParsingTask: NSBlockOperation? deinit { _associatedParsingTask?.cancel() } //MARK: - Overridden required override init(data: NSData) { super.init(data: data) } // still unsafe to call within the delegate callbacks override func parse() -> Bool { var parsingResult = false if (_associatedParsingTask == nil) { let parsingTask = NSBlockOperation(block: {() -> Void in parsingResult = super.parse() }) _associatedParsingTask = parsingTask // making it synchronous in order to return the result // of the super''s parse call _serialQueue.addOperations([parsingTask], waitUntilFinished: true) } return parsingResult } override func abortParsing() { if let parsingTask = _associatedParsingTask { parsingTask.cancel() _associatedParsingTask = nil } super.abortParsing() } // MARK: - Introduced // safe to use everywhere as it doesn''t force the calling thread to wait until this me thod returns func parse(completion completion:(Bool) -> Void) -> Void { var parsingResult = false if (_associatedParsingTask == nil) { let parsingTask = NSBlockOperation(block: {() -> Void in parsingResult = super.parse() }) parsingTask.completionBlock = { () -> Void in completion(parsingResult) } _associatedParsingTask = parsingTask // making it synchronous in order to return the result // of the super''s parse call _serialQueue.addOperation(parsingTask) } } }

PD: la idea es más o menos la misma que sugirió @CrimeZone.