2013-04-08 16 views
7

Próbuję odczytać dane z błędu standardowego z NSTask w Cocoa przy użyciu waitForDataInBackgroundAndNotify. Poniższy kod odczytuje strumień, więc działa już częściowo.NSFileHandleDataAvailableNotification pliki wielokrotnie, bez nowych danych (w wyniku bardzo wysokie użycie procesora)

Mam problem jest to, że czasami NSFileHandleDataAvailableNotification zaczyna wielokrotnie wypalania (tysiące razy na sekundę) bez nowych danych na wszystkich ([data length] zwrotów 0). Mój proces zaczyna wtedy używać dużo procesora, spowalniając maszynę do zatrzymania. Czy ktokolwiek z was uderzył coś takiego w przeszłości? Z góry dziękuję.

/** 
* Start reading from STDERR 
* 
* @private 
*/ 

- (void)startReadingStandardError { 
    NSFileHandle *fileHandle = [_task.standardError fileHandleForReading]; 
    [[NSNotificationCenter defaultCenter] addObserver:self 
              selector:@selector(errorData:) 
               name:NSFileHandleDataAvailableNotification 
               object:fileHandle]; 
    [fileHandle waitForDataInBackgroundAndNotify]; 
} 

/** 
* Fired whenever new data becomes available on STDERR 
* 
* @private 
*/ 

-(void) errorData: (NSNotification *) notification 
{ 
    NSFileHandle *fileHandle = (NSFileHandle*) [notification object]; 
    NSData *data = [fileHandle availableData]; 

    if ([data length]) { 
     // consume data 
    } 

    [fileHandle waitForDataInBackgroundAndNotify]; 
} 

Odpowiedz

9

Więc skończyło się to samemu. Zgodnie z NSFileHandle Class Reference, jeśli obiekt zwrócony przez availableData ma długość 0, oznacza to, że osiągnięto koniec pliku. Nie zajmowałem się tą sprawą poprawnie. Naprawiono to dla mnie:

/** 
* Fired whenever new data becomes available on STDERR 
* 
* @private 
*/ 

-(void) errorData: (NSNotification *) notification 
{ 
    NSFileHandle *fileHandle = (NSFileHandle*) [notification object]; 
    NSData *data = [fileHandle availableData]; 

    if ([data length]) { 
     // consume data 
     // ... 

     [fileHandle waitForDataInBackgroundAndNotify]; 
    } else { 
     // EOF was hit, remove observer 
     [[NSNotificationCenter defaultCenter] removeObserver:self name:NSFileHandleDataAvailableNotification object:fileHandle]; 
    } 
} 
+0

Należy również zamknąć plik. –

+4

Uwielbiam jak nigdzie w dokumentach nie wspomniano, że 'waitForDataInBackgroundAndNotify' musi być wywołany ponownie po otrzymaniu powiadomienia. Dzięki! –