2013-11-23 50 views
0

我一直在iOS中進行客戶端 - 服務器通信,但我在這裏遇到了一個問題,我有一些麻煩要理解。NSStream過早關閉

我寫了兩個基本功能:一個發送數據到服務器,另一個接收來自服務器的數據。每個人都有一個叫做超時參數,允許使當前線程休眠和喚醒每0.25秒,直到達到超時:

-(ReturnCode) send : (NSData*)data :(int)timeOut 
    { 
    if(![self isConnectionOpened]) return KO; 

    float timer = 0; 

    while(![_outputStream hasSpaceAvailable]) 
    { 
     [NSThread sleepForTimeInterval:0.25]; 
     timer+=0.25; 
     if(timer == timeOut) break; 
    } 

    int ret = 0; 
    if([_outputStream hasSpaceAvailable]){ 
     int lg = [data length]; 

     ret = [_outputStream write:[data bytes] maxLength:lg]; 

     if(ret == -1) return KO; 
     else return OK; 
    } 

    return TIMEOUT; 
} 

- (ReturnCode) receive : (NSData**)data : (int)timeOut : (int)maxLength 
{ 
    uint8_t buffer[maxLength]; 
    int len; 
    NSMutableData* dataReceived = [[NSMutableData alloc] init]; 
    if(! [self isConnectionOpened]) return KO; 

    float timer = 0; 
    while(![_inputStream hasBytesAvailable]) 
    { 
     [NSThread sleepForTimeInterval:0.25]; 
     timer+=0.25; 
     if(timer == timeOut) break; 
    } 

    if(![_inputStream hasBytesAvailable]) return TIMEOUT; 

    while ([_inputStream hasBytesAvailable]) { 
     len = [_inputStream read:buffer maxLength:sizeof(buffer)]; 
     if (len > 0) { 
      [dataReceived appendBytes:buffer length:len]; 
      *data = dataReceived; 
      return OK; 
     } 
    } 
    return KO; 

} 

隨着iPhone 4 + iOS6的,一切都會好的。但在iOS7下,出於某些模糊原因,inputstream和outputstream過早關閉(NSStreamEventErrorOccurred引發)。事實是,如果我在從服務器接收數據並使代碼運行之前放置一個斷點,它可以正常工作,讀/寫流不會錯誤地關閉。

所以我認爲這是一個同步的問題,但我不明白爲什麼...如果任何人有想法,請幫助...

回答

1

我發現在我的問題來自何處。

其實,要仔細考慮排定輸入流和輸出流的位置。事實上,有人告訴我,蘋果的對象必須在主線程上執行的,所以我安排他們這樣說:

dispatch_async(dispatch_get_main_queue(),^{ 
    [_inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 
    [_outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 

    [_inputStream open]; 
    [_outputStream open]; 
}); 

但實際上,它似乎更安排他們從當前線程的電流回路,而不是在主線上發送排程動作:

 [_inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 
    [_outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 

    [_inputStream open]; 
    [_outputStream open];