Yet another problem with NSTask and NSPipe
Yet another problem with NSTask and NSPipe
- Subject: Yet another problem with NSTask and NSPipe
- From: Dragan Milić <email@hidden>
- Date: Sun, 22 Apr 2007 14:16:04 +0200
Hello all,
I know this topic has been beaten do death during past seven years,
yet after reading from archives all that I could find about it and
after struggling for couple of days, I'm not able to solve it, hence
need some help.
The situation is quite standard. I run hdiutil inside NSTask. The
goal is to get information on an image and use it afterwards. For
that reason I use -plist option of the hdiutil, so the NSTask should do:
hdiutil imageinfo -plist image_name
Not to spend too many words, here is the part of code that I use:
NSPipe *stdInPipe = [NSPipe pipe];
NSPipe *stdOutPipe = [NSPipe pipe];
NSFileHandle *stdOutHandle = [stdOutPipe fileHandleForReading];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(outPipeDataAvailable:)
name:NSFileHandleReadCompletionNotification
object:stdOutHandle];
NSTask *task = [[[NSTask alloc] init] autorelease];
[task setStandardInput:stdInPipe];
[task setStandardOutput:stdOutPipe];
[task setArguments:[NSArray arrayWithObjects:@"hdiutil",
@"imageinfo", @"-plist", imageName, nil]];
[task setLaunchPath:@"/usr/bin/env"];
[stdOutHandle readInBackgroundAndNotify];
[self setStdOutData:[NSMutableData data]];
[task launch];
[task waitUntilExit];
int terminationStatus = [task terminationStatus];
[task release];
if (terminationStatus != 0) {
// error handling
}
[[NSNotificationCenter defaultCenter]
removeObserver:self
name:NSFileHandleReadCompletionNotification
object:nil];
NSDictionary *properties = [[[[NSString alloc] initWithData:stdOutData
encoding:NSASCIIStringEncoding] autorelease] propertyList];
...
...
The notification method:
- (void)outPipeDataAvailable:(NSNotification *)notification
{
NSData *data = [[notification userInfo]
objectForKey:NSFileHandleNotificationDataItem];
if ([data length] > 0) {
[stdOutData appendData:data];
[[notification object] readInBackgroundAndNotify];
}
}
When I run this code on 900Mhz G3 iBook, it runs just fine. I can
notice that the whole plist dictionary is read and stuffed into
stdOutData in a few readings, meaning that the notification method
gets called several times.
But, if I run this code on much faster computer, e.g. 2.0GHz Intel
Core 2 Duo MacBook, I notice that the notification method gets called
only once, and then the task finishes its execution, leaving me with
incomplete output that cannot be parsed into -[NSString propertyList]
method. Like the task has been executed so quickly that the output
pipe hasn't had a chance to be read to the end.
I've tried various approaches and everything that I could find on
mailing lists on NSTask and NSPipe topics and that I could think of,
including pooling file descriptor of stdOutHandle with select() and
setting it to O_NONBLOCK, reading in separate thread, putting delays
in the main method, postponing removing of object from notification
center until later, postponing releasing of NSTask object until
later,... None of it helped.
Can anyone point to me the correct way of doing this, which will
discard all possible timing issues? Any help is much appreciated.
Cheers,
Milke
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden