AFHTTPClient: object de respuesta de análisis

Acabo de comenzar a usar AFNetworking y estoy intentando aprender a hacerlo correctamente. AFHTTPClient el AFHTTPClient y he creado mi propio MyAppClient con la URL base correcta.
Me estoy comunicando con mi server con la request HTTP POST y la respuesta del server con xml.

para enviar una request hago:

  [[MyAppClient shanetworkingClient] postPath:somePath parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) { // need to parse the data here... } failure:^(AFHTTPRequestOperation *operation, NSError *error) { // NSLog(@"%@", [error localizedDescription]); }]; 

Pocas preguntas:

  1. ¿Por qué el AFHTTPClient utiliza la operación si de todos modos está utilizando una NSURLConnection asíncrona que no bloquea el hilo principal?

  2. Después de get los datos necesito analizarlos, ¿debería ahora crear una nueva operación para analizar los datos?
    Me parece que sería mejor analizar los datos también en la operación y luego devolver los objects analizados, ¿no?

  3. En el mismo tema, tengo una class XMLParser genérica personalizada que obtiene un NSData y lo analiza en NSDictionary , y me gustaría utilizarlo para todas las respuestas, ¿cómo puedo integrarlo en AFHTTPClient AFHTTPRequestOperation para que la respuesta ya sea analizado

¿Por qué el AFHTTPClient utiliza la operación si de todos modos está utilizando una connection NSURLC asíncrona que no bloquea el hilo principal?

Esta es realmente una excelente pregunta.

De hecho, no es necesaria una class viable de "HTTPRequestOperation" para subclass de NSOperation . Es muy probable que el layout de AFHTTPRequestOperation se base en el layout "original" presentado por un ingeniero de Apple, "Quinn", que inventó el primer "layout de reference" con su class QHTTPOperation y también proporcionó una serie de muestras invaluables, que siguen siendo muy recomendables y vale la pena echarle un vistazo. Este primer layout subclassa una NSOperation y encapsula un object NSURLConnection .

Este layout tiene una serie de ventajas:

  • Como se trata de una subclasss de NSOperation , la request de networking parece una "operación asíncrona". Esto significa básicamente que la request de networking tiene los principales methods de start y cancel y tiene un manejador de finalización para indicar el resultado final de la request. Esta API genérica es importante para una operación de networking asíncrona , de modo que se convierte en una operación asíncrona más general.

  • Como es una class, encapsula todas las variables de estado relacionadas para una request. Por ejemplo, la request, la respuesta, los datos de respuesta, un error (si corresponde) y un par de variables de estado más relevantes. El "object de request de networking" se vuelve muy útil de usar, a diferencia del enfoque delegado donde comienza a ser difícil cuando se debe manejar más de una request en los methods delegates en un object delegado.

  • Un object NSOperation puede colocarse en una NSOperationQueue . Esto permite definir el order de las requestes, y específicamente cualquier otra operación, y el número de operaciones (requestes) simultáneas activas si tiene muchas.

  • Con NSOperation uno puede definir dependencies más o less complejas entre otras operaciones, lo que le permite agregar una capa adicional de "lógica comercial". De vez en cuando, esto resulta muy útil para resolver problemas asíncronos más complejos.

Entonces, la pregunta de por qué una NSURLConnection ya asíncrona estaba encapsulada en una subclass de NSOperation son estas ventajas antes mencionadas. La razón era nunca envolverlo como una function síncrona en una NSOperation para que se pueda ejecutar en un NSOperationQueue .

De hecho, hay una gran idea errónea sobre esto. Parece que muchas personas piensan que los methods de la operación de request de networking se ejecutarán en el context de ejecución de NSOperation (por ejemplo, cuando se agrega a un NSOperationQueue). Sin embargo, este no es el caso (con posibles pequeñas excepciones entre las otras implementaciones). El context de ejecución de los methods (en su mayoría methods de delegado de NSULRConnection ) es un hilo privado dedicado que será creado por la subclass NSOperation . Las funciones de nivel inferior de la base NSURLConnection también se ejecutan en su context de ejecución privada (uno o más subprocesss) de todos modos.

Solo el método de start se ejecutará en el context de ejecución de la operación, que vuelve rápidamente. Es decir, si hay una queue (por ejemplo, la queue de despacho o un NSOperationQueue) donde se envió la operación, solo el método de start se ejecuta en el context de ejecución de la queue.

Sin embargo, el estado isFinished se postergará hasta el punto en que la request de networking haya finalizado. Este estado tiene un significado importante para otros objects de NSOperation y un NSOperationQueue : indica la queue y otras operaciones en las que se ha completado esta request.

Por lo tanto, NSOperation es less un vehículo para definir el context de ejecución de las funciones de una request de networking, sino más bien un medio para organizar y configurar relaciones con otras operaciones.


Después de get los datos necesito analizarlos, ¿debería ahora crear una nueva operación para analizar los datos? Me parece que sería mejor analizar los datos también en la operación y luego devolver los objects analizados, ¿no?

Bien, puedes hacer eso. Sin embargo, no consideraría esta una buena decisión de layout: una operación solo debe procesar una tarea en particular . La operación de networking es una, y la tarea de análisis es otra tarea, que también puede ser una operación.

Una razón para esto es que las operaciones pueden "clasificarse" con respecto a los resources del sistema que requieren principalmente : CPU, memory, IO, etc. Combinar diferentes "types de tareas" hace que sea imposible aprovecharlos para asociarlos a queues dedicadas para controlar Utilización de los resources del sistema (ver más abajo).

Bueno, puedes hacer que una tarea de análisis sea una operación, por supuesto. Si esto tiene sentido, depende, sin embargo:

La decisión de si desea hacer una tarea (o function) en particular una NSOperation depende de las siguientes consideraciones:

  • Una "Operación" está justificada, si esa tarea puede tardar mucho time en finalizar (desde la perspectiva del usuario) y, por lo tanto, usted (como desarrollador) quiere que el usuario dé la oportunidad de cancelar la tarea: (usted restring: una operación asíncrona tiene el método principal cancel )

  • Otra razón sería asociar una operación a un context particular de ejecución que esté asociado a un recurso de sistema compartido y limitado en particular: como CPU, memory, IO, etc. Esto le permite controlar, por ejemplo, el número de operaciones ejecutadas en paralelo que requieren un cierto recurso del sistema Digamos que tiene una tarea "Disk bound". En este caso, puede crear un NSOperationQueue cuyo número de operación simultánea sea 1, y darle un "rol" particular y un nombre adecuado, por ejemplo, "DiskBoundQueue". La queue le ayuda a controlar la creación y el inicio de las operaciones, y fuerza un límite del número de operaciones de ejecución paralelas para que el recurso del sistema restringido no se agote. Luego, se agregarían operaciones "enlazadas al disco" solo al "DiskBoundQueue" dedicado. Dado que un disco funciona subóptimo cuando se accede desde diferentes tareas simultáneamente, el número de operaciones simultáneas se establece en 1. Es decir, estas queues dedicadas ayudan a optimizar la utilización de los resources del sistema.

  • Si tiene dependencies entre las operaciones, diga que desea iniciar la operación C solo si la operación A Y la operación B ha finalizado correctamente. NSOperation proporciona un medio para establecer dichas dependencies.

  • Otro motivo podría ser controlar el acceso concurrente a los resources compartidos: si hay varias operaciones que acceden a un determinado recurso compartido (un ivar, por ejemplo) que se agregan a un NSOperationQueue serie, el acceso al recurso compartido se serializa y, por lo tanto, "subprocesss seguro". Sin embargo, si la simultaneidad es el único requisito, preferiría usar el enfoque más simple utilizando queues de despacho y bloques.

Entonces, y para ser más preciso con respecto a su pregunta: no, un NSOperation probablemente sea demasiado grande. Puede que sea mejor utilizar una queue de despacho dedicada, posiblemente una serial que también resuelva el acceso simultáneo de resources compartidos.


En el mismo tema, tengo una class XMLParser genérica personalizada que obtiene un NSData y lo analiza en NSDictionary, y me gustaría utilizarlo para todas las respuestas, ¿cómo puedo integrarlo en AFHTTPClient AFHTTPRequestOperation para que la respuesta ya sea analizado

Un enfoque viable simplemente iniciaría el analizador XML dentro del controller de finalización de una AFHTTPRequestOperation o el AFClient, por ejemplo.

Si tiene otra operación que depende del resultado del analizador XML, un enfoque es encapsular el analizador XML en una NSOperation y, a continuación, hacer que la otra operación dependa de la operación del analizador XML. (Sin embargo, hay otras soluciones más simples para tales dependencies)

  1. Esto no tiene sentido inmediatamente. Mi conjetura es que el uso de mecanismos estándar proporciona el mejor performance. Sin embargo, los bloques success / failure también se ejecutan en la operación.

  2. Hago todo el análisis en los bloques de éxito de las operaciones. Si usa JSON, también puede configurar AFNetworking para hacer la des- / serialization automáticamente para usted. Es posible que desee convertir esos dictionarys y matrices en classs más inteligentes.

  3. Echa un vistazo a AFJSONRequestOperation . Puede darle algunas pistas.

1) En AFNetworking: la operación es el nivel más granular. Puede iniciarlo o enquelos. AFHTTPClient es excelente si está enviando requestes. Mira la operación en queue

2) AFNetworking lo mantiene modular. Esencialmente, no estás atado a su analizador. Puede usar cualquier analizador xml para analizar datos. Aunque me gusta (DCKeyValue) [https://github.com/dchohfi/KeyValueObjectMapping] para analizar tus datos y convertirlos directamente en objects.

3) No puede analizar automáticamente como RestKit, pero la respuesta 2 debería ayudarlo.