NSTask's real-time output

前端 未结 2 1970
情话喂你
情话喂你 2020-12-25 15:00

I have a PHP script which has mutliple sleep() commands. I would like to execute it in my application with NSTask. My script looks like this:

相关标签:
2条回答
  • 2020-12-25 15:25

    For reference, here is ughoavgfhw's answer in swift.

    override func awakeFromNib() {
        // Setup the task
        let task = NSTask()
        task.launchPath = "/usr/bin/php"
        task.arguments = ["-r", "echo \"first\n\"; sleep(1); echo \"second\n\"; sleep(1); echo \"third\n\";"]
    
        // Pipe the standard out to an NSPipe, and set it to notify us when it gets data
        let pipe = NSPipe()
        task.standardOutput = pipe
        let fh = pipe.fileHandleForReading
        fh.waitForDataInBackgroundAndNotify()
    
        // Set up the observer function
        let notificationCenter = NSNotificationCenter.defaultCenter()
        notificationCenter.addObserver(self, selector: "receivedData:", name: NSFileHandleDataAvailableNotification, object: nil)
    
        // You can also set a function to fire after the task terminates
        task.terminationHandler = {task -> Void in
               // Handle the task ending here
        }
    
        task.launch()
    }
    
    func receivedData(notif : NSNotification) {
        // Unpack the FileHandle from the notification
        let fh:NSFileHandle = notif.object as NSFileHandle
        // Get the data from the FileHandle
        let data = fh.availableData
        // Only deal with the data if it actually exists
        if data.length > 1 {
        // Since we just got the notification from fh, we must tell it to notify us again when it gets more data
            fh.waitForDataInBackgroundAndNotify()
            // Convert the data into a string
            let string = NSString(data: data, encoding: NSASCIIStringEncoding)
            println(string!)
        }
    }
    

    This construct will be necessary if your task produces lots of output into the pipe. Simply calling pipe.fileHandleForReading.readDataToEndOfFile() will not work because the task is waiting for the pipe to be emptied so it can write more while your program is waiting for the end of the data. Thus, your program will hang. This notification and observer construct allows the pipe to be read asynchronously and thus prevents the aforementioned stalemate.

    0 讨论(0)
  • 2020-12-25 15:25

    You can use NSFileHandle's waitForDataInBackgroundAndNotify method to receive a notification when the script writes data to its output. This will only work, however, if the interpreter sends the strings immediately. If it buffers output, you will get a single notification after the task exits.

    - (void)awakeFromNib {
        NSTask *task = [[NSTask alloc] init];
        [task setLaunchPath: @"/usr/bin/php"];
    
        NSArray *arguments;
        arguments = [NSArray arrayWithObjects: @"-r", @"echo \"first\n\"; sleep(1); echo \"second\n\"; sleep(1); echo \"third\n\";", nil];
        [task setArguments: arguments];
    
        NSPipe *p = [NSPipe pipe];
        [task setStandardOutput:p];
        NSFileHandle *fh = [p fileHandleForReading];
        [fh waitForDataInBackgroundAndNotify];
    
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receivedData:) name:NSFileHandleDataAvailableNotification object:fh];
    
        [task launch];
    
    }
    
    - (void)receivedData:(NSNotification *)notif {
        NSFileHandle *fh = [notif object];
        NSData *data = [fh availableData];
        if (data.length > 0) { // if data is found, re-register for more data (and print)
            [fh waitForDataInBackgroundAndNotify];
            NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"%@" ,str);
        }
    }
    
    0 讨论(0)
提交回复
热议问题