2012-04-20 190 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