NSURLConnection的委托方法
EDIT2 - 改写问题NSURLConnection的委托方法
我想要做的一些背景Web服务通信。我使用Sudzc作为HTTPRequests的的处理程序和它的工作原理是这样的:
SudzcWS *service = [[SudzcWS alloc] init];
[service sendOrders:self withXML:@"my xml here" action:@selector(handleOrderSending:)];
[service release];
它发送一些XML的web服务,和响应(在这其中,布尔)中规定的选择的处理:
- (void)handleOrderSending:(id)value
{
//some controls
if ([value boolValue] == YES)
{
//my stuff
}
}
当我试图在我的sendOrders:withXML:action:
方法上使用Grand Central Dispatch时,我注意到选择器没有被调用。我相信其中的原因是NSURLConnection委托消息被发送到创建连接的线程但是线程不会生存那么长时间,它会在方法结束时结束,从而杀死任何到委托的消息。
问候
EDIT1 [request send]
方法:
- (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]];
//
// }
//});
}
被注释掉是我尝试了各种事情的部分。最后一部分工作,但我不知道这是一个好方法。在类的NURLConnection
委托方法,会出现以下情况:
- (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];
}
委托无法执行,因为它的线程是死亡时-(void)send
完成发送消息。
我已经从这两个链接SO NURLConnection question和original一个帮助。
这对我的代码来说似乎并不危险,我将自行承担风险。谢谢。
任何建议仍然欢迎,当然。
另外感谢Pingbat花时间尝试和帮助。
sendOrders
的方法定义表明它已被设计为以异步方式执行请求。你应该看看sendOrders: withXML: action:
的执行情况,看看是否是这种情况。
没有看到使用GCD或SudzcWS代码的实现,很难说出了什么问题。尽管有上述警告,但以下几点可能会有用。
看起来您可能会在完成之前释放SudzcWS *service
。
以下几点:除非SudzcWS保留本身
SudzcWS *service = [[SudzcWS alloc] init];
dispatch_async(aQueue, ^{
[sevice sendOrders:self withXML:xml action:@selector(handleOrderSending:)];
}
[service release];
可能会失败。您异步分派块,将其放入队列中,并继续执行该方法。 service
已发布,并在块执行前或service
正在等待Web服务器的响应时取消分配。
除非另有说明,否则调用选择器将在它所调用的同一个线程上执行该选择器。做这样的事情:
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];
}
应确保双方sendOrders:
方法和handleOrderSending:
队列上aQueue
执行和service
直到它已执行的选择不会被释放。
这将需要你保持一个指向service
,以便handleOrderSending:
可以释放它。您可能还想考虑简单地挂在单个SudzcWS实例上,而不是每次要使用它时创建和释放一个实例,这应该会使您的内存管理变得更加轻松,并且有助于保持对象图的紧密性。
非常感谢。首先,释放'服务'并没有什么不同。其次,不幸的是,这两种方法不能以任何方式在同一队列中运行。最后,'sendOrders:withXML:action:'的作用方式是检查'action'对象是否为nil并运行'performSelector:'。所以现在我试图在该类中使用GCD(发送HTTPRequest的类)而不是在这里。 – 2012-04-24 07:29:23
如果它正在运行'[object performSelector:selector]',那么在这种情况下,它相当于'[object handleOrderSending:]'。这意味着该方法将在发送消息的同一队列上执行。你能发布SudzcWS的代码吗?这听起来好像它已经在为你做一些工作,这可能解释了这种混乱。 你如何确定哪些队列正在运行? – mjmdavis 2012-04-24 08:55:28
看到我编辑的问题。当我在处理程序类中使用它时,GCD工作正常,但不在'[service sendOrders:withXML:action:]'上。我只是为什么而困惑。 – 2012-04-24 10:38:57