rharder
Do not read this sign.
An earlier thread had information on using NSTimer-s to read from an NSPipe attached to an NSTask. This required regular polling and reading from the NSPipe which seems like kind of a silly way to do it. Apparently there's a better way, and boy am I glad it's there. I'll share it with you.
Let's assume you have some controller class that's going to start up the NSTask and do something with the NSPipe you read. Maybe you're just going to display the results in an NSTextView that you created in Project Builder.
In the controller's .h file, let's declare some variables:
Of course you would have put the _task in there anyway, right, but we want to have access to the _fileHandle that will become very important soon.
As always we launch the NSTask:
Now you'll be notified when the file handle (and thus the pipe attached to the task) has data to read. Oh wait, no you won't. We have to register with the NSNotificationCenter.
Make up an init method like this:
Of course you may need to add your own stuff too. Don't forget to unregister when you dealloc:
So what does our readPipe method look like? This:
Note that at the end we have to tell the file handle again that we want to be notified of changes, but we check to make sure that the _task isn't nil (assuming we did that somewhere).
Now isn't active notification much better than polling?
Let me know, y'all, if I have any errors.
-Rob
Let's assume you have some controller class that's going to start up the NSTask and do something with the NSPipe you read. Maybe you're just going to display the results in an NSTextView that you created in Project Builder.
In the controller's .h file, let's declare some variables:
Code:
NSTask *_task;
NSFileHandle *_fileHandle;
As always we launch the NSTask:
Code:
NSPipe *pipe = [NSPipe pipe];
_fileHandle = [pipe fileHandleForReading];
[_fileHandle readInBackgroundAndNotify];
_task = [[NSTask alloc] init];
[_task setLaunchPath:@"/bin/ls"];
[_task setStandardOutput: pipe];
[_task setStandardError: pipe];
// arguments if you want 'em
[_task launch];
Make up an init method like this:
Code:
-(id)init
{
[super init];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector( readPipe: )
name:NSFileHandleReadCompletionNotification
object:nil];
return self;
}
Code:
-(void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
Code:
-(void)readPipe: (NSNotification *)notification
{
NSData *data;
NSString *text;
if( [notification object] != _fileHandle )
return;
data = [[notification userInfo]
objectForKey:NSFileHandleNotificationDataItem];
text = [[NSString alloc] initWithData:data
encoding:NSASCIIStringEncoding];
// Do something with your text
// ...
[text release];
if( _task )
[_fileHandle readInBackgroundAndNotify];
}
Now isn't active notification much better than polling?
Let me know, y'all, if I have any errors.
-Rob