2009-12-13 8 views
0

J'ai besoin d'attendre une réponse d'un webservice SOAP, je fais appel via un NSURLConnection comme je l'ai besoin de manipuler les données retournées puis le retourner de ma classe à la classe d'appel ..NSURLConnection - Est-il possible d'attendre/bloquer une requête?

Voici mon code :

#import <Foundation/Foundation.h> 


@interface UsersBLL : NSObject { 

NSMutableData *webData; 
NSMutableString *soapResults; 
NSXMLParser *xmlParser; 
BOOL *recordResults; 
NSNumber *EmailCount; 
} 

@property(nonatomic, retain) NSMutableData *webData; 
@property(nonatomic, retain) NSMutableString *soapResults; 
@property(nonatomic, retain) NSXMLParser *xmlParser; 



-(int)checkEmailAddress:(NSString*)emailAddress; 
@end 

#import "UsersBLL.h" 


@implementation UsersBLL 
@synthesize webData; 
@synthesize soapResults; 
@synthesize xmlParser; 

-(id)init { 
self = [super init]; 
return self; 
} 

-(int)checkEmailAddress:(NSString*)emailAddress { 
// Build the SOAP envelope 
NSString *soapMessage = [NSString stringWithFormat: 
     @"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" 
     "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n" 
     "<soap:Body>\n" 
     "<CheckEmailAddress xmlns=\"http://tempuri.org/\">\n" 
     "<EmailAddress>%@</EmailAddress>\n" 
     "</CheckEmailAddress>\n" 
     "</soap:Body>\n" 
     "</soap:Envelope>\n", emailAddress]; 

NSLog(soapMessage); 

NSURL *url = [NSURL URLWithString:@"http://photoswapper.mick-walker.co.uk/UsersService.asmx?op=CheckEmailAddress"]; 
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url]; 
NSString *msgLength = [NSString stringWithFormat:@"%d", [soapMessage length]]; 

[theRequest addValue: @"text/xml; charset=utf-8" forHTTPHeaderField:@"Content-Type"]; 
[theRequest addValue: @"http://tempuri.org/CheckEmailAddress" forHTTPHeaderField:@"SOAPAction"]; 
[theRequest addValue: msgLength forHTTPHeaderField:@"Content-Length"]; 
[theRequest setHTTPMethod:@"POST"]; 
[theRequest setHTTPBody: [soapMessage dataUsingEncoding:NSUTF8StringEncoding]]; 

NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self]; 

if(theConnection) 
{ 
    webData = [[NSMutableData data] retain]; 
} 
else 
{ 
    NSLog(@"theConnection is NULL"); 
} 
NSLog(@"%@", EmailCount); 
} 

-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response 
{ 
[webData setLength: 0]; 
} 
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 
{ 
[webData appendData:data]; 
} 
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error 
{ 
NSLog(@"ERROR with theConenction"); 
[connection release]; 
[webData release]; 
} 
-(void)connectionDidFinishLoading:(NSURLConnection *)connection 
{ 
NSLog(@"DONE. Received Bytes: %d", [webData length]); 
NSString *theXML = [[NSString alloc] initWithBytes: [webData mutableBytes] length:[webData length] encoding:NSUTF8StringEncoding]; 
NSLog(theXML); 
[theXML release]; 

if(xmlParser) 
{ 
    [xmlParser release]; 
} 

xmlParser = [[NSXMLParser alloc] initWithData: webData]; 
[xmlParser setDelegate: self]; 
[xmlParser setShouldResolveExternalEntities: YES]; 
[xmlParser parse]; 

[connection release]; 
[webData release]; 
} 

-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *) namespaceURI qualifiedName:(NSString *)qName 
    attributes: (NSDictionary *)attributeDict 
{ 
if([elementName isEqualToString:@"CheckEmailAddressResult"]) 
{ 
    if(!soapResults) 
    { 
    soapResults = [[NSMutableString alloc] init]; 
    } 
    recordResults = TRUE; 
} 
} 
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string 
{ 
if(recordResults) 
{ 
    [soapResults appendString: string]; 
} 
} 
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName 
{ 
if([elementName isEqualToString:@"CheckEmailAddressResult"]) 
{ 
    recordResults = FALSE; 
    NSNumberFormatter *formatter = [[NSNumberFormatter alloc]init]; 
    EmailCount = [formatter numberFromString:soapResults]; 
      [formatter release]; 
    [soapResults release]; 
    soapResults = nil; 
} 
} 

@end 

CheckEmailAddress est déclarée renvoyer une valeur entière (je sais qu'il ne retourne rien dans l'exemple ci-dessus). Ce que je veux idéalement, c'est par la méthode CheckEmailAddress, renvoyer la valeur récupérée du service Web. Cependant, comme l'appel NSURLConnection n'attend pas que la requête soit terminée, je ne peux pas le faire.

Je serais reconnaissant si quelqu'un pouvait me donner des idées pour des solutions de contournement.

Répondre

2

La solution la plus simple utiliserait [NSURLConnection sendSynchronousRequest:returningResponse:error:].

Il ne permet pas autant de contrôle que l'approche que vous avez prise, mais est généralement suffisant pour la plupart des applications.

+1

Juste ce que j'allais suggérer - sachez bien que si elle ne retourne jamais pour une raison quelconque, votre programme pendre. – wadesworld

+0

Oui, je reçois souvent cela en référence à un hôte qui semble exister mais qui ne répond pas ou n'est pas accessible pour une raison quelconque. Mais définir le délai d'attente à une valeur raisonnable a fait l'affaire la plupart du temps. – Alfonso

+0

Mes excuses pour le suivi avec une autre question, mais je ne vois pas comment sendSynchronousRequest peut m'aider à obtenir les données, analyser et retourner le résultat de ma méthode Cordialement –

0

Vous avez deux choix:

  • Utilisez +[NSURLConnection sendSynchronousRequest:returningResponse:error:]

  • Planifier la connexion en mode runloop personnalisé, et exécuter la boucle dans ce mode jusqu'à ce que les données arrivent ou si vous avez besoin d'annuler la connexion

0

tout dépend du niveau de asynchronisme dont vous avez besoin:

  • Si c'est OK pour rester bloqué pendant la demande entière, vous pouvez utiliser

    +[NSURLConnection sendSynchronousRequest:returningResponse:error:] 
    

    Mais, comme le suggère Wade, soyez prudent d'ajouter un délai d'attente à votre NSURLRequest, sinon la connexion pourrait blocs et votre application va se bloquer.

  • Sinon, vous pouvez simplement utiliser NSNotificationCenter. Mais vous devez être prudent avec les conditions de course sur vos données, surtout si vous gérez plusieurs demandes

1

Je viens de poster une solution qui enveloppe une NSURLConnection asynchrone pour être en mesure de bloquer le thread appelant. Si vous avez besoin de plus de contrôle que l'[NSURLConnection sendSynchronousRequest:returningResponse:error:] standard, vous pouvez vérifier ce lien sur StackOverflow:

NSURLConnection blocking wrapper implemented with semaphores