5

Tengo varias vistas que hacen el mismo NSURLRequest/NSURLConnection request. Idealmente, para obtener un poco de reutilización de código, me gustaría tener algún tipo de "proxy" que haga todo el trabajo subyacente de crear/ejecutar la solicitud/conexión (asíncrona), configurar todos los métodos delegados, etc. , así que no tengo que copiar todos los manejadores de métodos delegados NSURLConnection en cada vista. En primer lugar, ¿este enfoque de diseño es razonable? En segundo lugar, ¿cómo haría para hacer algo así?NSURLConnection NSURLSolicitud de proxy para llamadas al servicio web asíncronas

Para obtener un poco de información de antecedentes, intenté esto y lo puse a "funcionar", sin embargo, no parece ejecutarse de forma asíncrona. He creado un archivo Proxy.h/m, que cuenta con métodos de instancia para las diferentes llamadas de servicio web (y también contiene los métodos de delegado NSURLConnection):

@interface Proxy : NSObject { 

    NSMutableData *responseData; 
    id<WSResponseProtocol> delegate; 
} 

- (void)searchForSomethingAsync:(NSString *)searchString delegate:(id<WSResponseProtocol>)delegateObj; 

@property (nonatomic, retain) NSMutableData *responseData; 
@property (assign) id<WSResponseProtocol> delegate; 

@end 

El WSResponseProtocol se define como tal:

@protocol WSResponseProtocol <NSObject> 

@optional 
- (void)responseData:(NSData *)data; 
- (void)didFailWithError:(NSError *)error; 

@end 

Para usar esto, el controlador de vista simplemente necesita cumplir con el protocolo WSResponseProtocol, para capturar la (s) respuesta (s). Hacer la llamada de servicio web se realiza de este modo:

Proxy *p = [[Proxy alloc] init]; 
[p searchForSomethingAsync:searchText delegate:self]; 
[p release]; 

me puede dar más código, pero el resto se puede suponer. Antes de llamar, comienzo a "Animar" a un spinner UIActivityIndicatorView. Pero la ruleta nunca gira. Si simplemente pongo los métodos de delegado de NSURLConnection directamente en el controlador de vista, el girador gira. Entonces, me hace pensar que mi implementación no se está ejecutando de forma asíncrona. ¿Alguna idea/pensamiento aquí?

Respuesta

22

Su enfoque es razonable, sin embargo, no estoy seguro de por qué está creando su propio protocolo. Esto no es necesario. Todo lo que necesita para implementar esto está en el documentation on NSURLConnection de Apple. Si toma el código de esa página donde se crea una instancia de NSURLConnection y hace que la conexión sea ivar en lugar de solo crearla como una variable local, puede comparar los objetos de conexión en cada uno de los métodos de devolución de llamada y responder en consecuencia. Por ejemplo, tomemos el código de la documentación y cambiar el objeto de conexión a una Ivar:

// create the request 
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.apple.com/"] 
         cachePolicy:NSURLRequestUseProtocolCachePolicy 
        timeoutInterval:60.0]; 
// create the connection with the request 
// and start loading the data 
theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self]; 
if (theConnection) { 
    // Create the NSMutableData that will hold 
    // the received data 
    // receivedData is declared as a method instance elsewhere 
    receivedData=[[NSMutableData data] retain]; 
} else { 
    // inform the user that the download could not be made 
} 

La variable theConnection es nuestro Ivar. A continuación, se puede comprobar de esta manera:

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 
{ 
    if (connection == theConnection) 
    { 
     // do something with the data object. 
     [connectionSpecificDataObject appendData:data]; 
    } 
} 

Por supuesto que puede ponerlo en práctica la creación de su propio protocolo como usted sugiere y luego llamar de vuelta al delegado que cumpla con el protocolo, pero puede ser mejor simplemente instanciando su objeto usando un selector de éxito y error que puede verificar. Algo como esto:

- (void)connectionDidFinishLoading:(NSURLConnection *)connection 
{ 
    if (connection == theConnection) 
    { 
     if (delegate && [delegate respondsToSelector:successSelector]) 
      [delegate performSelector:successSelector 
          withObject:connectionSpecificDataObject]; 
    } 
    [connection release]; 
} 

Dónde dataDidDownloadSelector es una variable de instancia SEL que se establece cuando creó su delegado de descarga donde todos este código está contenido - el objeto proxy. Algo como esto:

Proxy *p = [[Proxy alloc] init]; 
[p searchForSomethingAsync:searchText 
        delegate:self 
      successSelector:@selector(didFinishWithData:) 
       failSelector:@selector(didFailWithError:)]; 

implementar sus selectores de la siguiente manera:

- (void)didFinishWithData:(NSData*)data; 
{ 
    // Do something with data 
} 

- (void)didFailWithError:(NSError*)error 
{ 
    // Do something with error 
} 

Esto se ha convertido en una respuesta más larga de lo que pretendía. Avísame si no tiene sentido y puedo intentar aclararlo.

Saludos,

+0

Ah - ¡muy bien! Veo lo que dices: tu solución eliminaría la necesidad de un protocolo. ¡Mucho más directo! ¡Gracias por eso! Creo que estoy empezando a calentarme a la solución que sugirió Kendal, es decir, tener NSURLConnections sincrónicas envueltas en una NSOperation y lanzadas en una cola. Esa solución puede ser una solución más directa al problema de crear un marco de llamadas a servicios web sincronizados, aunque mi enfoque + su visión aún es viable. – tbehunin

+0

Revertir mi comentario anterior. Este enfoque es el enfoque con el que voy versus las NSURLConnections sincrónicas dentro de una NSOperation. NSURLConnection ya proporciona el subprocesamiento que necesito sin ponerlo en una NSOperation. Además, después de leer más blogs, la autenticación NSURLConnections + sincrónica no proporciona tantos "ganchos" como las llamadas asincrónicas. – tbehunin

+0

Donde \ cómo se declara receivedData. La documentación sigue diciendo que está declarada en otra parte, pero no brinda información sobre cómo hacerlo. –

1

Su código como está, creo que no haría nada - se suelta el proxy justo después de inicializar, por lo que ni siquiera se ejecuta.

Un enfoque que me gusta usar son las llamadas NSURLConnection sincrónicas, dentro de una NSOperation que a su vez es administrada por un NSOperationQueue. Hago el objeto que la cola vive en Singleton, así que solo accedo a la instancia desde cualquier lugar y le digo cuando necesito que se inicie una nueva conexión.

+0

¡Agradable! Nunca pensé en ese enfoque de llamadas NSURLConnection sincrónicas envueltas en una NSOperation. Creo que esta será la solución que estoy buscando. Sin embargo, con esta solución, necesita una forma de recuperar información. Aquí hay un enlace a otra respuesta de SO a este problema: http://stackoverflow.com/questions/1297733/cocoa-return-information-from-nsoperation – tbehunin

+0

Para pasar los resultados, generalmente almaceno el resultado de los datos en algún lugar central a través de un singleton, y/o devuelva el objeto a cualquier persona interesada envuelto en una notificación (puede envolver cualquier objeto en el diccionario de notificación userInfo). –

Cuestiones relacionadas