2013-04-08 13 views
7

Sto tentando di leggere i dati dall'errore standard di uno NSTask in Cocoa utilizzando waitForDataInBackgroundAndNotify. Il seguente codice legge lo stream, quindi funziona già parzialmente.NSFileHandleDataAvailableNotifica i file ripetutamente senza nuovi dati (con conseguente utilizzo della CPU molto elevato)

Il problema è che talvolta lo NSFileHandleDataAvailableNotification inizia a sparare ripetutamente (migliaia di volte al secondo) senza alcun nuovo dato ([data length] restituisce 0). Il mio processo inizia quindi a utilizzare molta CPU, rallentando la macchina. Qualcuno di voi ha colpito qualcosa del genere prima in passato? Grazie in anticipo.

/** 
* 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]; 
} 

risposta

9

Quindi, ho finito per capirlo da solo. In base allo NSFileHandle Class Reference, se l'oggetto NSData restituito da availableData ha una lunghezza di 0, significa che è stata raggiunta la fine del file. Non stavo gestendo correttamente questo caso. Questo lo ha risolto per me:

/** 
* 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

Si consiglia inoltre di chiudere il file. –

+4

Mi piace il fatto che da nessuna parte nei documenti sia menzionato che "waitForDataInBackgroundAndNotify" deve essere richiamato dopo l'arrivo della notifica. Grazie! –

Problemi correlati