2012-04-01 15 views
1
Arbeits

Also, das ist mein Code:Async Ausführung von Shell-Befehl nicht richtig

- (void)runCmd:(NSString *)cmd withArgs:(NSArray *)args 
{ 
    NSLog(@"\nRunning ::\n\tCmd : %@\n\tArgs : %@",cmd, args); 
    [theSpinner start]; 
    if (task) 
    { 
     [task interrupt]; 

    } 
    else 
    { 
     task = [[NSTask alloc] init]; 
     [task setLaunchPath:cmd]; 

     [task setArguments:args]; 

     [pipe release]; 

     pipe = [[NSPipe alloc] init]; 
     [task setStandardOutput:pipe]; 

     NSFileHandle* fh = [pipe fileHandleForReading]; 

     NSNotificationCenter* nc; 

     nc = [NSNotificationCenter defaultCenter]; 
     [nc removeObserver:self]; 
     [nc addObserver:self 
       selector:@selector(dataReady:) 
        name:NSFileHandleReadCompletionNotification 
       object:fh]; 
     [nc addObserver:self selector:@selector(dataAvailable:) name:NSFileHandleDataAvailableNotification object:fh]; 
     [nc addObserver:self 
       selector:@selector(taskTerminated:) 
        name:NSTaskDidTerminateNotification 
       object:task]; 

     [task launch]; 
     [fh readInBackgroundAndNotify]; 
    } 
} 

- (void)dataAvailable:(NSNotification*)n 
{ 
    NSLog(@"Data Available : %@",n); 
} 

- (void)dataReady:(NSNotification*)n 
{ 
    NSData* d; 

    d = [[n userInfo] valueForKey:NSFileHandleNotificationDataItem]; 

    NSLog(@"Data Ready : %@",n); 

    if ([d length]) 
    { 
     NSLog(@"Data Ready : %@",[[NSString alloc] initWithData:d encoding:NSUTF8StringEncoding]); 
    } 
} 

- (void) taskTerminated:(NSNotification*)note 
{ 
    NSLog(@"Task Terminated : %@",note); 
    [task release]; 
    task = nil; 
    [theSpinner stop]; 

    NSAlert *alert = [[[NSAlert alloc] init] autorelease]; 
    [alert setMessageText:[NSString stringWithFormat:@"Command finished"]]; 

    [alert runModal]; 
} 

Ich habe versucht, einen Befehl ausgeführt wird (zB der PHP-Interpreter bei /usr/bin/php) mit Argumenten (zB die Datei interpretiert werden php test.php).

Die Sache ist die:

  • Das Skript fein läuft
  • ABER, Ich erhalte eine Data Ready und Task Terminated Benachrichtigung, bevor ich habe es geschafft, alle Ausgaben zu bekommen. (Ich meine, die dataReady: Funktion holt nur der erste Teil des
    Ausgang und dem Rest der es nirgends zu finden ist ...)

Ich möchte im Grunde genommen, asynchron zu lesen, alle Ausgangs - Während der Befehl ausgeführt wird.

Irgendwelche Ideen? Was mache ich falsch?

Danke!

Antwort

4

Sie verwenden readInBackgroundAndNotify, um Ihre Lesung zu planen. Diese Methode liest nur einen Puffer voller Daten und benachrichtigt. Sie müssen entweder readInBackgroundAndNotify in Ihrer Benachrichtigungsmethode erneut aufrufen, um weitere Daten zu lesen, oder Sie müssen readToEndOfFileInBackgroundAndNotify verwenden, wenn Sie alle Daten gleichzeitig erhalten möchten.

+0

Absolut korrekt. (Habe es mir selbst ausgedacht, übrigens, aber vielen Dank trotzdem! ;-)) –

1

Es gibt eine neue API seit 10.7, so dass Sie die Verwendung von NSNotifications vermeiden können.

task.standardOutput = [NSPipe pipe]; 
[[task.standardOutput fileHandleForReading] setReadabilityHandler:^(NSFileHandle *file) { 
    NSData *data = [file availableData]; // this will read to EOF, so call only once 
    NSLog(@"Task output! %@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); 

    // if you're collecting the whole output of a task, you may store it on a property 
    [self.taskOutput appendData:data]; 
}]; 

WICHTIG:

Wenn Ihre Aufgabe beendet, müssen Sie readabilityHandler Block auf Null gesetzt; Andernfalls wird eine hohe CPU-Auslastung auftreten, da der Lesevorgang nie beendet wird.

[task setTerminationHandler:^(NSTask *task) { 

    // do your stuff on completion 

    [task.standardOutput fileHandleForReading].readabilityHandler = nil; 
    [task.standardError fileHandleForReading].readabilityHandler = nil; 
}];