2

First of all, when debugging and running in Xcode everything works as expected.

But when I try to "share" my app, i.e. make a release build, my NSTask won't output any standardOutput while standardErrors ARE put out. How is that possible?

My code

- (id)initWithWindow:(NSWindow *)window {
    self = [super initWithWindow:window];
    if (self) {
        // Initialization code here.
    }
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(readPipe:) name:NSFileHandleReadCompletionNotification object:nil];
    return self;
}


-(void) watchFile:(NSNotification *)notification {
        NSString *path = [[notification userInfo] valueForKey:@"path"];

        task = [[NSTask alloc] init];
        [task setLaunchPath:@"/usr/bin/compass"];
        [task setCurrentDirectoryPath:path];

        NSArray *arguments;
        arguments = [NSArray arrayWithObjects: @"watch",@"--boring", nil];
        [task setArguments: arguments];

        NSPipe *outPipe, *errPipe;
        outPipe = [NSPipe pipe];
        errPipe = [NSPipe pipe];
        [task setStandardOutput: outPipe];
        [task setStandardError: errPipe];
        [task setStandardInput: [NSPipe pipe]];

        standardHandle = [outPipe fileHandleForReading];
        [standardHandle readInBackgroundAndNotify];

        errorHandle = [errPipe fileHandleForReading];
        [errorHandle readInBackgroundAndNotify];

        [self setSplitterPosition:0.0f];

        [task launch];

    }

-(void)readPipe:(NSNotification *)notification {
        NSLog(@"reading pipe");
        NSData *data;
        NSString *text;

        if(!([notification object] == standardHandle) && !([notification object] == errorHandle)) {
            return;
        } 

        data = [[notification userInfo] objectForKey:NSFileHandleNotificationDataItem];
        text = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];

        if ([data length] == 0) {
            //error
            [self setSplitterPosition:150.0f];
            return;
        }

        [terminalViewController updateTerminal:text];    
        if(![text isEqualToString:@"\n"]) [self growlAlert:text title:@"Compapp"];

        [text release];
        if(task) [[notification object] readInBackgroundAndNotify];
    }
ThomasM
  • 2,647
  • 3
  • 25
  • 30

3 Answers3

0

/usr/bin/compass is not a binary installed in the standard installation of OSX (I don't have any binary named compass in my /usr/bin on my Mac)

So it seems quite logical that when your app is running on another Mac -- that does not have /usr/bin/compass installed -- and you try to run this task, it can't find it and only output some error on stderr.

AliSoftware
  • 32,623
  • 6
  • 82
  • 77
  • That's not really the problem. I receive custom error messages from the binary itself. Besides I've only tested it on my own computer. – ThomasM Nov 24 '11 at 09:58
  • Ok you were talking about "when I try to share my app" so I assumed it was on another Mac. – AliSoftware Nov 24 '11 at 10:38
  • Did you try to retain the standardHandle and errorHandle variables, to be sure they are still valid in your `readPipe:` method? The difference between Debug and Release also being code optimization (and sometimes a small increase of execution speed then too) it may explain that in Debug your variables have not been autoreleased yet but in Release they are. Try to add some NSLogs to log the different ivars you use and check they are still valid in Release build. – AliSoftware Nov 24 '11 at 10:41
  • Yeah, I just said that cause that's how it's called in XCode. Sorry if that wasn't clear :) – ThomasM Nov 24 '11 at 10:42
  • Well in the code in my question. The log "reading pipe" is never called for standardOutput, so I'm guessing it has something to do with the NSFileHandleReadCompletionNotification never being fired, or something like that? – ThomasM Nov 24 '11 at 10:48
  • Can't see where you add yourself as an observer for this NSNotification? You sure you added both pipes to the NSNotificationCenter? (would seem strange anyway that it still works in Debug not in Release) – AliSoftware Nov 24 '11 at 16:33
  • It's on the very first line of the code I posted. I updated it a little to show where it's being called. I didn't add "both" pipes, it just listens for the NSFileHandleReadCompletionNotification. And then in the readPipe: method, I check to see which pipe is being handled.. – ThomasM Nov 25 '11 at 10:28
  • Before your edit, the first line of your code was adding the `watchFile:` selector to the `"ConfigAdded"` notification, not adding `readPipe:` to the `NSFileHandleReadCompletionNotification`, hence my question. – AliSoftware Nov 25 '11 at 13:38
  • Ok so then sorry but I don't see what could then possibly be wrong in Release but not in Debug… Maybe try to put your `addObserver:` method into your `watchFile:` code for both pipes (specifying the object in the `addObserver` parameter instead of using `nil`), possibly also using two different `@selector`s (even if those selectors just `NSLog` some trace and then call both the same common method at the end)? I'm not sure why it would change anything but it's worth trying, isn't it? – AliSoftware Nov 26 '11 at 01:31
  • Good thinking, but to no avail. Damn, this is driving me crazy. The way I see it, NSFileHandleReadCompletionNotification isn't being fired for reading standardOutput... What the hell is up with that? – ThomasM Nov 28 '11 at 09:05
0

If you mean after release you are trying to debug, you need to create a file called Entitlements.plist and set Can be debugged before you build and archive.

omarmaris
  • 96
  • 2
  • 9
0

if this is still an open issue for you, then checkout the answer I posted at this link: How to use a determinate NSProgressIndicator to check on the progress of NSTask? - Cocoa

it provides a good template for creating an async NSTask and for reading from standard output or standard error.

Community
  • 1
  • 1
CocoaEv
  • 2,984
  • 20
  • 21
  • Hey, thanks, I just tried your code, but I get the exact same results. My program runs perfect when i build and run in Xcode, but when I Archive and then Share as application, I get no textdata back. My process seems to run fine, but I don't get ANY output.. – ThomasM Feb 14 '12 at 15:14
  • does it work perfectly on your xcode machine when you run the archived version? does the target machine have the same OS command on it that you are using on your xcode machine? I prefer to set a notification for each file handle like this: [nc addObserver:self selector:@selector(notifiedForStdOutput:) name:NSFileHandleReadCompletionNotification object:fhOutput]; where you name the file handle and process it separately rather then a single generic method. I would try logging the data then open console and see what is happening. – CocoaEv Feb 14 '12 at 22:58
  • I am testing on the exact same machine, so everything should be the same. And I already tried to NSLog data, but it's like those notifications are never dispatched (or received). – ThomasM Feb 17 '12 at 10:19
  • not sure what is going on. I have a couple of apps in prod using the approach I recommended. I'm willing to try and compile your xcode project if you would like another set of eyes. – CocoaEv Feb 18 '12 at 01:04
  • I'd greatly appreciate that! Can I send it to you somehow? – ThomasM Feb 20 '12 at 10:59