NSURLConnection - 是否可以等待/阻止请求?
我需要等待来自 SOAP Web 服务的响应,我通过 NSURLConnection 进行调用,因为我需要操作返回的数据,然后将其从我的类返回到调用类。
这是我的代码:
#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 被声明为返回一个整数值(我知道它在上面的示例中没有返回任何内容)。
我理想中想要的是通过 CheckEmailAddress 方法,返回从 Web 服务检索到的值。但是,由于调用 NSURLConnection 不会等到请求完成,因此我无法执行此操作。
如果有人能给我任何潜在的解决方法的想法,我将不胜感激。
I need to wait for a response from a SOAP webservice, I am calling via a NSURLConnection as I need to manipulate the data being returned and then return it from my class to the calling class..
Here is my 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 is declared as returning an integer value (I know it returns nothing in the sample above).
What I ideally want, is through the CheckEmailAddress method, return the value retrieved from the web service. However as the call NSURLConnection does not wait until the request has completed, I cannot do it.
I would be grateful if anyone could give me any potential ideas for workarounds.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
最简单的解决方案是使用
[NSURLConnection sendSynchronousRequest:returningResponse:error:]
。它不像您所采用的方法那样允许那么多的控制,但通常对于大多数应用程序来说已经足够了。
The simplest solution would be using
[NSURLConnection sendSynchronousRequest:returningResponse:error:]
.It does not allow as much control as the approach you've taken, but is usually enough for most applications.
我刚刚发布了一个解决方案,它包装了一个异步 NSURLConnection 以便能够阻止调用线程。如果您需要比标准
[NSURLConnection sendSynchronousRequest:returningResponse:error:]
更多的控制,您可以查看 StackOverflow 上的此链接:使用信号量实现的 NSURLConnection 阻塞包装器
I have just posted a solution which wraps an asynchronous NSURLConnection to be able to block the calling thread. In case you need more control than the standard
[NSURLConnection sendSynchronousRequest:returningResponse:error:]
you can check out this link on StackOverflow:NSURLConnection blocking wrapper implemented with semaphores
您有两种选择:
使用
+[NSURLConnection sendSynchronousRequest:returningResponse:error:]
以自定义runloop模式安排连接,并以该模式运行循环,直到数据到达或需要取消连接
You have two choices:
Use
+[NSURLConnection sendSynchronousRequest:returningResponse:error:]
Schedule the connection in a custom runloop mode, and run the loop in that mode until the data arrives or you have need to cancel the connection
这完全取决于您需要的异步级别:
如果可以在整个请求期间保持阻塞,您可能需要使用
但是,正如 Wade 建议的那样,请小心为 NSURLRequest 添加超时,否则连接可能会阻塞并且您的应用程序将挂起。
如果没有,您可以简单地使用 NSNotificationCenter。但是您必须小心数据的竞争条件,特别是当您正在处理多个请求时
It all depends on the level of asynchronism you need:
If it's OK to stay blocked during the whole request you may want to use
But, as suggested by Wade, be careful to add a timeout to your NSURLRequest, otherwise the connection might blocks and your application will hang.
If not, you can simply use the NSNotificationCenter. But you must be careful with race conditions over your data, specially if you are handling multiple requests