2012-04-20 137 views
4

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完成发送消息。

回答

2

我已经从这两个链接SO NURLConnection questionoriginal一个帮助。

这对我的代码来说似乎并不危险,我将自行承担风险。谢谢。

任何建议仍然欢迎,当然。

另外感谢Pingbat花时间尝试和帮助。

2

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实例上,而不是每次要使用它时创建和释放一个实例,这应该会使您的内存管理变得更加轻松,并且有助于保持对象图的紧密性。

+0

非常感谢。首先,释放'服务'并没有什么不同。其次,不幸的是,这两种方法不能以任何方式在同一队列中运行。最后,'sendOrders:withXML:action:'的作用方式是检查'action'对象是否为nil并运行'performSelector:'。所以现在我试图在该类中使用GCD(发送HTTPRequest的类)而不是在这里。 – 2012-04-24 07:29:23

+0

如果它正在运行'[object performSelector:selector]',那么在这种情况下,它相当于'[object handleOrderSending:]'。这意味着该方法将在发送消息的同一队列上执行。你能发布SudzcWS的代码吗?这听起来好像它已经在为你做一些工作,这可能解释了这种混乱。 你如何确定哪些队列正在运行? – mjmdavis 2012-04-24 08:55:28

+0

看到我编辑的问题。当我在处理程序类中使用它时,GCD工作正常,但不在'[service sendOrders:withXML:action:]'上。我只是为什么而困惑。 – 2012-04-24 10:38:57

相关问题