Re: Reading return values from NSTask
Re: Reading return values from NSTask
- Subject: Re: Reading return values from NSTask
- From: Shawn Erickson <email@hidden>
- Date: Sun, 28 Dec 2003 16:02:02 -0800
On Dec 28, 2003, at 2:40 PM, KLW wrote:
Hello,
I'm trying to execute a perl script from within my Cocoa application
and get its return value (not its exit status). I've tried two
approaches: 1) using a c system() call (which, I believe will only net
me an exit status), or 2) using NSTask, like so:
<ugly code>
NSString * argument = [[NSString alloc] initWithCString: argv[1]];
NSTask *task = [[NSTask alloc] init];
NSFileHandle *readHandle = [[NSFileHandle alloc] init];
NSData *inData = [[NSData alloc] init];
NSMutableString *outString = [[NSMutableString alloc] init];
NSMutableArray *args = [NSMutableArray array];
NSLog(@"Passing: %@",argument);
[args addObject:argument];
[task setStandardOutput:readHandle];
[task setLaunchPath:@"/path/to/my/perl/script.pl"];
[task setArguments:args];
[task launch];
</ugly code>
So far so good. The task launches correctly, and the console gets the
correct output from the perl script. However, when I try to read the
output to Cocoa, I run into trouble. I can't figure out (having looked
at the NSTask page about thirty times) how to read ordinary output
back into a variable. My attempt is here:
<really ugly code>
if ((inData = [readHandle availableData]) && [inData length]) {
outString = [outString initWithData:inData
encoding:NSASCIIStringEncoding];
// outString = [inData description];
}
[task terminate];
NSString *result = [[NSString alloc] initWithFormat: @"result:
%@",outString];
NSLog(result);
</really ugly code>
Do you wait for the task to complete before trying to read in data? You
code sample doesn't show that.
I do notice some strange things in your code snippet above... You
allocate and init inData and outString at the beginning yet replace
them later on in you code without releasing what you inited. You appear
to believe that you have to allocate those before that can be assigned
to... you don't. I suggest reading up on Objective-C a little more to
better understand the difference between objects and references to
objects. Also it is cleaner to use NSArray's arrayWithObject or
arrayWithObjects then creating a NSMutableArray to later simply add a
single item to it that you had on hand when you created the array in
the first place. Finally you need not call terminate on the task, it
will exist when it is done running (assuming the script you are running
exists).
Anyway this is one example of how I use NSTask in a project of mine...
- (void)initSwapFileRootDirectory
{
NSData* data;
NSTask* ls = [[[NSTask alloc] init] autorelease];
[ls setStandardOutput:[NSPipe pipe]];
[ls setLaunchPath:@"/bin/sh"];
[ls setArguments:[NSArray arrayWithObjects:...]];
[ls launch];
[ls waitUntilExit];
data = [[[ls standardOutput] fileHandleForReading] availableData];
if ((data != nil) && [data length]) {
NSString* tmpString = [[[NSString alloc] initWith
Data:data
encoding:NSUTF8StringEncoding] autorelease];
...
}
}
Or done another way...
...
eater = [[NSTask alloc] init];
[eater setStandardOutput:[NSPipe pipe]];
[eater setLaunchPath:eaterPath];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(eaterTerminated:)
name:NSTaskDidTerminateNotification
object:nil];
NSFileHandle* outFileHandle = [[eater standardOutput]
fileHandleForReading];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(readFromStandardOutput:)
name:NSFileHandleDataAvailableNotification
object:outFileHandle];
[outFileHandle waitForDataInBackgroundAndNotify];
[eater launch];
...
- (void)readFromStandardOutput:(NSNotification*)aNotification
{
NSString *bytes;
NSData *data;
if (eater == nil) return;
if ((data = [[aNotification object] availableData]) == nil) return;
bytes = [[[NSString alloc] initWith
Data:data
encoding:NSASCIIStringEncoding] autorelease];
[textField setStringValue:[NSString stringWithFormat: @"Memory
Eater PID:%d - Eaten: %ld (MB)",
[eater
processIdentifier],
[bytes
intValue] / (1024*1024)]];
[[[eater standardOutput] fileHandleForReading]
waitForDataInBackgroundAndNotify];
}
-Shawn
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.