NSURLConnection delegate methods on thread background

EDIT2 – Reescribe la pregunta

Quiero hacer un poco de comunicación de service web en segundo plano. Estoy usando Sudzc como el manejador de HTTPRequests y funciona así:

SudzcWS *service = [[SudzcWS alloc] init]; [service sendOrders:self withXML:@"my xml here" action:@selector(handleOrderSending:)]; [service release]; 

Envía algunos XML al service web, y la respuesta (en este, un boolean) se maneja en el selector especificado:

 - (void)handleOrderSending:(id)value { //some controls if ([value boolValue] == YES) { //my stuff } } 

Cuando intenté usar Grand Central Dispatch en mi sendOrders:withXML:action: method, noté que no se llama al selector. Y creo que la razón de esto es que los posts delegates de NSURLConnection se envían al hilo del cual se crea la connection. Pero el hilo no vive tanto time, termina cuando el método termina, matando cualquier post al delegado.

Saludos

EDIT1 [request send] método:

 - (void) send { //dispatch_async(backgroundQueue, ^(void){ // If we don't have a handler, create a default one if(handler == nil) { handler = [[SoapHandler alloc] init]; } // Make sure the network is available if([SoapReachability connectedToNetwork] == NO) { NSError* error = [NSError errorWithDomain:@"SudzC" code:400 userInfo:[NSDictionary dictionaryWithObject:@"The network is not available" forKey:NSLocalizedDescriptionKey]]; [self handleError: error]; } // Make sure we can reach the host if([SoapReachability hostAvailable:url.host] == NO) { NSError* error = [NSError errorWithDomain:@"SudzC" code:410 userInfo:[NSDictionary dictionaryWithObject:@"The host is not available" forKey:NSLocalizedDescriptionKey]]; [self handleError: error]; } // Output the URL if logging is enabled if(logging) { NSLog(@"Loading: %@", url.absoluteString); } // Create the request NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL: url]; if(soapAction != nil) { [request addValue: soapAction forHTTPHeaderField: @"SOAPAction"]; } if(postData != nil) { [request setHTTPMethod: @"POST"]; [request addValue: @"text/xml; charset=utf-8" forHTTPHeaderField: @"Content-Type"]; [request setHTTPBody: [postData dataUsingEncoding: NSUTF8StringEncoding]]; if(self.logging) { NSLog(@"%@", postData); } } //dispatch_async(dispatch_get_main_queue(), ^(void){ // Create the connection conn = [[NSURLConnection alloc] initWithRequest: request delegate: self]; if(conn) { NSLog(@" POST DATA %@", receivedData); receivedData = [[NSMutableData data] retain]; NSLog(@" POST DATA %@", receivedData); } else { // We will want to call the onerror method selector here... if(self.handler != nil) { NSError* error = [NSError errorWithDomain:@"SoapRequest" code:404 userInfo: [NSDictionary dictionaryWithObjectsAndKeys: @"Could not create connection", NSLocalizedDescriptionKey,nil]]; [self handleError: error]; } } //}); //finished = NO; // while(!finished) { // // [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; // // } //}); } 

Las partes que se comentan son las varias cosas que probé. La última parte funcionó, pero no estoy seguro de si es una buena manera. En el método delegado NURLConnection de la class, esto es lo que sucede:

 - (void)connectionDidFinishLoading:(NSURLConnection *)connection { NSError* error; if(self.logging == YES) { NSString* response = [[NSString alloc] initWithData: self.receivedData encoding: NSUTF8StringEncoding]; NSLog(@"%@", response); [response release]; } CXMLDocument* doc = [[CXMLDocument alloc] initWithData: self.receivedData options: 0 error: &error]; if(doc == nil) { [self handleError:error]; return; } id output = nil; SoapFault* fault = [SoapFault faultWithXMLDocument: doc]; if([fault hasFault]) { if(self.action == nil) { [self handleFault: fault]; } else { if(self.handler != nil && [self.handler respondsToSelector: self.action]) { [self.handler performSelector: self.action withObject: fault]; } else { NSLog(@"SOAP Fault: %@", fault); } } } else { CXMLNode* element = [[Soap getNode: [doc rootElement] withName: @"Body"] childAtIndex:0]; if(deserializeTo == nil) { output = [Soap deserialize:element]; } else { if([deserializeTo respondsToSelector: @selector(initWithNode:)]) { element = [element childAtIndex:0]; output = [deserializeTo initWithNode: element]; } else { NSString* value = [[[element childAtIndex:0] childAtIndex:0] stringValue]; output = [Soap convert: value toType: deserializeTo]; } } if(self.action == nil) { self.action = @selector(onload:); } if(self.handler != nil && [self.handler respondsToSelector: self.action]) { [self.handler performSelector: self.action withObject: output]; } else if(self.defaultHandler != nil && [self.defaultHandler respondsToSelector:@selector(onload:)]) { [self.defaultHandler onload:output]; } } [self.handler release]; [doc release]; [conn release]; conn = nil; [self.receivedData release]; } 

El delegado no puede enviar posts porque el hilo se muere cuando finaliza -(void)send .

    La definición del método para sendOrders sugiere que ya está diseñado para ejecutar requestes de forma asíncrona. Debería echar un vistazo a la implementación de sendOrders: withXML: action: para saber si este es el caso.

    Sin ver su implementación usando GCD o el código de SudzcWS, es difícil decir qué va mal. A pesar de las advertencias anteriores, lo siguiente puede ser útil.

    Parece que puede estar lanzando el SudzcWS *service antes de que se complete.

    El seguimiento:

     SudzcWS *service = [[SudzcWS alloc] init]; dispatch_async(aQueue, ^{ [sevice sendOrders:self withXML:xml action:@selector(handleOrderSending:)]; } [service release]; 

    Podría fallar a less que SudzcWS se retenga. Envía su bloque de forma asíncrona, se coloca en una queue y continúa la ejecución del método. service se libera y se desasigna antes de que el bloque se ejecute o mientras el service está esperando una respuesta del server web.

    A less que se especifique lo contrario, al llamar a un selector se ejecutará ese selector en el mismo subprocess al que se llama. Hacer algo como:

     SudzcWS *service = [[SudzcWS alloc] init]; dispatch_async(aQueue, ^{ [sevice sendOrders:self withXML:xml action:@selector(handleOrderSending:)]; } - (void)handleOrderSending:(id)value { //some controls //your stuff [service release]; } 

    debe asegurarse de que tanto el método sendOrders: como el handleOrderSending: se ejecuten en la queue aQueue y ese service no se libere hasta que haya ejecutado el selector.

    Esto requerirá que mantenga un puntero para el service para que handleOrderSending: pueda lanzarlo. También es posible que desee considerar simplemente colgar en una sola instancia de SudzcWS en lugar de crear y liberar una cada vez que desee usarlo, esto debería facilitar la administración de la memory y ayudar a mantener el gráfico de objects apretado.

    He tenido la ayuda de estos enlaces SO NURLConnection question y el original .

    No parece arriesgado para mi código y lo usaré bajo mi propio riesgo. Gracias.

    Cualquier recomendación es bienvenida, por supuesto.

    Un agradecimiento adicional a Pingbat por tomarse el time para tratar de ayudar.