4ntoine
4ntoine

Reputation: 20410

Getting process output using NSTask on-the-go?

I'd like to get NSTask output as soon as it appears not waiting until process finishes. I've found this answer but how it should be modified to get data ASAP? I think i should run background thread and wait for output all the time somehow.

Upvotes: 1

Views: 1348

Answers (1)

Martin R
Martin R

Reputation: 539685

You can register for the NSFileHandleDataAvailableNotification notification to read asynchronously from the task output. Example:

NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:@"/bin/ls"];
[task setCurrentDirectoryPath:@"/"];

NSPipe *stdoutPipe = [NSPipe pipe];
[task setStandardOutput:stdoutPipe];

NSFileHandle *stdoutHandle = [stdoutPipe fileHandleForReading];
[stdoutHandle waitForDataInBackgroundAndNotify];
id observer = [[NSNotificationCenter defaultCenter] addObserverForName:NSFileHandleDataAvailableNotification
                                                                object:stdoutHandle queue:nil
                                                            usingBlock:^(NSNotification *note) 
{
    // This block is called when output from the task is available.

    NSData *dataRead = [stdoutHandle availableData];
    NSString *stringRead = [[NSString alloc] initWithData:dataRead encoding:NSUTF8StringEncoding];
    NSLog(@"output: %@", stringRead);

    [stdoutHandle waitForDataInBackgroundAndNotify];
}];

[task launch];
[task waitUntilExit];
[[NSNotificationCenter defaultCenter] removeObserver:observer];

Alternatively, you can read on a background thread, for example with GCD:

NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:@"/bin/ls"];
[task setCurrentDirectoryPath:@"/"];

NSPipe *stdoutPipe = [NSPipe pipe];
[task setStandardOutput:stdoutPipe];

NSFileHandle *stdoutHandle = [stdoutPipe fileHandleForReading];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
    NSData *dataRead = [stdoutHandle availableData];
    while ([dataRead length] > 0) {
        NSString *stringRead = [[NSString alloc] initWithData:dataRead encoding:NSUTF8StringEncoding];
        NSLog(@"output: %@", stringRead);
        dataRead = [stdoutHandle availableData];
    }
});

[task launch];
[task waitUntilExit];

Upvotes: 4

Related Questions