2012-04-24 67 views
2
.h 
@property (strong) NSString *reply; 

我有以下方法:NSURL連接sendAsynchronousRequest如何保存響應?

.m 
@synthesize reply; 

- (void)send 
{ 
[NSURLConnection sendAsynchronousRequest:[self request] 
       queue:[[NSOperationQueue alloc] init] 
       completionHandler: 
         ^(NSURLResponse *response, NSData *data, NSError *error)  
         { 
          if (error) 
          { 
           //NSLog(@"Error,%@", [error localizedDescription]); 
           [self setReply: [[NSString alloc] initWithString:[error localizedDescription]]]; 
          } 
          else 
          { 
           //NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]); 
           [self setReply: [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]]; 
          } 
         }]; 

} 

現在,我試圖從塊/處理程序返回一個值,但顯然這是不可能的(或者我還沒有想出的語法還)。

我試圖設置一個局部變量來獲得答覆(數據)的值,但它會產生錯誤。

錯誤沒有產生的唯一方法是使用類屬性。但是當我試圖讀取[自我回復]的價值時,它是空的,這使我認爲它從未設置。

據我所知,sendAsync函數是線程和異步的,所以是[自我答覆]的值爲空的原因,而當我使用sendSynchronousRequest,我總是得到答覆?

我做錯了什麼,以及如何從completionHandler內返回一個值?

編輯#1:在我看來,我做的事情非常錯誤。我正在追蹤代碼,當我使用同步發送時,一切正常。使用異步方式,對於sendAsynchronousRequest的實際調用從未執行,這讓我認爲該線程沒有被調用,因此它是空值。

編輯#2:我已經找到解決的辦法,通過增加以下內容:

[NSURLConnection sendAsynchronousRequest:[self request] 
       queue:[NSOperationQueue alloc] init 
       completionHandler: 
         ^(NSURLResponse *response, NSData *data, NSError *error)  
         { 
          if (error) 
          { 
           //NSLog(@"Error,%@", [error localizedDescription]); 
           [self setReply: [[NSString alloc] initWithString:[error localizedDescription]]]; 
          } 
          else 
          { 
           //NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]); 
           [self setReply: [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]]; 
          } 
         }]; 

[[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 2]]; 

不過,我不能完全肯定我理解它是如何工作的。我想象RunLoop會告訴異步操作運行2秒(我可以驗證,因爲在將日期間隔設置爲較低值時,由於使用活動服務器進行測試,我得到空響應)。我不明白的是,當我告訴RunLoop運行時,它永遠阻止一切,就好像當前線程永不終止一樣。

+0

我不明白的問題/問題。爲什麼不能從塊完成功能返回一個值? setReply函數有什麼作用?向我們顯示代碼 – Lefteris 2012-04-24 15:10:21

+0

設置斷點以查看數據是否有效或爲空。 你在正確的軌道上,這似乎有效,但你可能沒有得到可以使用的信息。 – 2012-04-24 15:28:21

+0

該塊被指定爲具有void返回類型,所以塊本身不能返回值 - 但爲什麼需要返回值?我猜你的setReply函數只是一個實例變量的setter?在這種情況下,您不需要從塊中返回任何內容,因爲當您設置回覆時將會捕獲響應。使用本地變量捕獲數據值時產生的錯誤是什麼?你應該能夠設置一個斷點來查看數據。另外,我會添加檢查您收到的響應代碼。 – tronbabylove 2012-04-24 15:29:06

回答

2

差不多一個月後,我找到了解決我的問題:

NSURLConnection* _connection = [[NSURLConnection alloc] initWithRequest:[self request] delegate:self startImmediately:NO]; 
    self.port = [NSPort port];                          
    self.runloop = [NSRunLoop currentRunLoop];                      
    [self.runloop addPort:self.port forMode:NSDefaultRunLoopMode]; 
    [_connection scheduleInRunLoop:self.runloop forMode:NSDefaultRunLoopMode]; 
    [_connection start]; 
    while (self.finished != YES) { 
     [self.runloop runUntilDate:[NSDate dateWithTimeIntervalSinceNow: 0.1]];                  
    } 
    [self.runloop removePort:[self port] forMode:NSDefaultRunLoopMode]; 
    [_connection unscheduleFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 

這奏效了我。請記住,我必須正確實施NSConnection的委託方法(didReceiveResponse,didReceiveData,didFailWithError,connectionDidFinishLoading)。 但它現在異步工作,不凍結用戶界面,並具有適當的錯誤報告。 希望它可以幫助有人卡住在同一問題

+1

如果你投了票 - 至少花時間說出原因 – 2014-10-03 23:04:56

0

你應該嘗試使用__block關鍵字爲你的財產回覆

@property (strong) __block NSString *reply; 

這個關鍵字,使你的財產,從寫塊內部的聲明。

編輯

提案,阻止主線程,直到收到響應或直到請求超時的方法:

//this block is used to define a waiting condition 
typedef BOOL (^ CheckBlock)(); 

- (BOOL)waitUntilBlockTrue:(CheckBlock)theBlock orTimeout:(int)timeout { 
    NSDate *waitingStartPoint = [NSDate date]; 
    BOOL stillNeedToWait = YES; 
    while (stillNeedToWait && theBlock()) { 
     stillNeedToWait = ([waitingStartPoint timeIntervalSinceNow]*(-1.0)) < timeout; 
    } 
    return stillNeedToWait; 
} 

爲了您的例子中,你會調用此方法:

[self waitUntilBlockTrue:^{ 
     //returns YES as long as the method should block 
     return (BOOL)(self.reply == nil); 
    } orTimeout:10]; 
+0

試過了,沒有什麼區別。我的猜測是主線程終止比異步發送操作更快結束。謝謝你告訴我這個,它很好理解。 – 2012-04-25 09:54:31

+1

那麼如果你正在使用這個異步調用,並且你希望主線程等待響應,你必須阻塞主線程。我在用SenTestCase編寫測試時遇到了這個問題。看看我用來阻塞主線程的方法。 – bas 2012-04-25 12:31:21

+0

非常感謝您花時間回覆並添加了代碼。不幸的是,我得不到它建立,因爲我得到一個錯誤的類型的參數傳遞給塊函數(從無符號字符BOOL無效塊指針轉換爲(布爾)^())。更重要的是,在我看來,我們正在以同樣的方式採用不同的方法。我在主隊列中添加了異步發送,然後告訴它運行10秒(我的超時)。是不是你在做什麼,除了你所做的一切將會阻止一旦返回值的阻塞? – 2012-04-26 09:34:19

2

擺脫runUntilDate,並嘗試使用[NSOperationQueue mainQueue],看看有沒有什麼變化anythi NG。

[NSURLConnection sendAsynchronousRequest:[self request] 
      queue:[NSOperationQueue mainQueue] 
      completionHandler: 
        ^(NSURLResponse *response, NSData *data, NSError *error)...  
+0

我試過了,沒有什麼區別。這實際上是我第一次嘗試它的方式。 – 2012-04-25 09:50:01