48

Estoy en el proceso de repensar mi enfoque de la arquitectura de solicitud de una gran aplicación que estoy desarrollando. Actualmente estoy usando ASIHTTPRequest para hacer solicitudes, pero dado que necesito muchos tipos de solicitudes diferentes como resultado de muchas acciones diferentes tomadas en diferentes controladores de vista, estoy tratando de encontrar el mejor sistema para organizar estas solicitudes.¿La mejor arquitectura para una aplicación de iOS que realiza muchas solicitudes de red?

Actualmente estoy creando "solicitantes" únicos que son retenidos por el delegado de la aplicación y me siento escuchando NSNotifications que indican que se debe realizar una solicitud; hacen la solicitud, escuchan la respuesta y envían una nueva NSNotificación con los datos de respuesta. Esto resuelve la mayoría de mis problemas, pero no maneja elegantemente solicitudes fallidas o solicitudes simultáneas al mismo solicitante único.

¿Alguien tiene éxito en el diseño de una arquitectura OO clara para hacer muchos tipos diferentes de solicitudes en una aplicación de iOS?

+2

Buena pregunta: He estado buscando una respuesta a esto también, como alguien que ha creado un administrador de conexión para NSURLConnection que funciona bien para una conexión pero no tan bien para varias. –

Respuesta

69

Después de haber probado varios enfoques, esta es una arquitectura que me está dando excelentes resultados, es fácil documentar, entender, mantener y extender:

  • que tienen un único objeto el cuidado de la conectividad de red, vamos a llámalo un "administrador de red". Normalmente, este objeto es un singleton (creado usando Matt Gallagher's Cocoa singleton macro).
  • Como usa ASIHTTPRequest (que siempre hago, maravillosa API) agrego un ASINetworkQueue ivar dentro de mi administrador de red. Hago que el administrador de red sea el delegado de esa cola.
  • Creo subclases de ASIHTTPRequest para cada tipo de solicitud de red que requiera mi aplicación (generalmente, para cada interacción REST backend o punto final SOAP). Esto tiene otro beneficio (ver detalles a continuación :)
  • Cada vez que uno de mis controladores requiere algunos datos (actualización, viewDidAppear, etc.), el administrador de red crea una instancia de la subclase ASIHTTPRequest requerida, y luego la agrega a la cola .
  • ASINetworkQueue se encarga de los problemas de ancho de banda (dependiendo de si está en 3G, EDGE o GPRS o Wifi, tiene más ancho de banda, y puede procesar más solicitudes, etc.). Esto es hecho por la cola, lo cual es genial (al menos, esa es una de las cosas que entiendo que esta cola hace, espero no estar equivocado :).
  • Cuando una solicitud finaliza o falla, se llama al administrador de red (recuerde, el administrador de red es el delegado de la cola).
  • El administrador de la red no sabe qué hacer con el resultado de cada solicitud; por lo tanto, simplemente llama a un método en la solicitud! Recuerde, las solicitudes son subclases de ASIHTTPRequest, por lo que puede simplemente colocar el código que gestiona el resultado de la solicitud (normalmente, la deserialización de JSON o XML en objetos reales, desencadenando otras conexiones de red, actualizando almacenes de datos centrales, etc.). Poner el código en cada subclase de solicitud por separado, utilizando un método polimórfico con un nombre común a través de las clases de solicitud, hace que sea muy fácil depurar y administrar en mi humilde opinión.
  • Finalmente, notifico a los controladores de arriba sobre eventos interesantes usando notificaciones; no es una buena idea usar un protocolo de delegado, porque en su aplicación normalmente tiene muchos controladores hablando con su administrador de red, y luego las notificaciones son más flexibles (puede tener varios controladores respondiendo a la misma notificación, etc.).

De todos modos, así es como lo he estado haciendo durante un tiempo, y francamente funciona bastante bien.Puedo extender el sistema horizontalmente, agregando más subclases ASIHTTPRequest cuando las necesito, y el núcleo del administrador de red permanece intacto.

Espero que ayude!

+0

¡buena respuesta! ¿cómo prueba su sistema? Otra gran preocupación mía es crear una arquitectura fácil de probar. – kevboh

+0

gracias, excelente explicación. – Epaga

+5

Una cosa rápida que viene a la mente es que podrías usar bloques en lugar de notificaciones si solo tienes una clase que esté interesada en tu respuesta. –

0

El proyecto fully-loaded es una buena lectura.

+0

He visto completamente cargada antes: maneja bien un problema específico, pero estoy buscando una solución que trate con diferentes tipos de solicitudes que tienen respuestas diferentes. La forma en que se manejan las solicitudes totalmente cargadas es similar a lo que he detallado en mi pregunta, con nsnotifications y asihttprequest haciendo el trabajo pesado. Estoy buscando algo más extensible y robusto, incluso si solo se trata de una forma creativa de organizar notificaciones y solicitudes. – kevboh

+1

El otro ejemplo de código en mi mente es la carpeta 'Networking' en la muestra de MVCNetworking de Apple, de la que no tengo ninguna experiencia para hacer ningún comentario. – ohho

+0

Interesante. Tendré que verificar esto. – kevboh

1

Así es como generalmente lo hago. Yo también tengo un objeto singleton utilizado para hacer solicitudes de red. Para las solicitudes que deben realizarse con frecuencia, tengo un NSOperationQueue que acepta AFHTTPRequestOperations (o AFJSONRequestOperations) ya que generalmente uso AFNetworking para realizar solicitudes. Para estos, hay una propiedad completionBlock and failureBlock que se ejecuta al éxito o al fracaso de la solicitud. En mi objeto singleton, tendría un método para iniciar una solicitud de red particular, y como parámetros para ese método, incluiría un bloque de éxito y falla que puede pasarse a los bloques definidos en el método. De esta forma, toda la aplicación puede realizar una solicitud de red, y el alcance de la aplicación en ese punto está disponible para el singleton en el bloque que se pasa al método. Por ejemplo ... (usando ARC)

 @implementation NetworkManager 

    -(void)makeRequestWithSuccess:(void(^)(void))successBlock failure:(void(^)(NSError *error))failureBlock 

    { 
     NSURL *url = [NSURL URLWithString:@"some URL"]; 

     NSURLRequest *request = [NSURLRequest requestWithURL:url]; 

     AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:request]; 

     [op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { 
      [responseObject doSomething]; 

      if (successBlock) 
       dispatch_async(dispatch_get_main_queue(), successBlock); 

     } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 

      if (failureBlock) 
       dispatch_async(dispatch_get_main_queue(), ^{ 
        failureBlock(error); 
       }); 
     }]; 

     [self.operationQueue addOperation:op]; 
    } 
@end 

Y siempre puede hacer que el bloque de éxito tome los parámetros que necesita para pasar.

Cuestiones relacionadas