2011-08-03 17 views
18

मेरे पास एक PHP स्क्रिप्ट है जिसमें mutliple sleep() आदेश हैं। मैं इसे अपने आवेदन में NSTask के साथ निष्पादित करना चाहता हूं। मेरे स्क्रिप्ट इस तरह दिखता है:एनएसटीस्क का रीयल-टाइम आउटपुट

echo "first\n"; sleep(1); echo "second\n"; sleep(1); echo "third\n"; 

मैं अपने काम से एसिंक्रोनस रूप से निष्पादित अधिसूचना का उपयोग कर सकते हैं:

- (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]; 

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskExited:) name:NSTaskDidTerminateNotification object:task]; 

    [task launch]; 

} 

- (void)taskExited:(NSNotification *)notif { 
    NSTask *task = [notif object]; 
    NSData *data = [[[task standardOutput] fileHandleForReading] readDataToEndOfFile]; 
    NSString *str = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; 
    NSLog(@"%@",str); 
} 

मेरे उत्पादन होता है (2 सेकंड के बाद, निश्चित रूप से):

2011-08-03 20:45:19.474 MyApp[3737:903] first 
second 
third 

मेरा सवाल है: मुद्रित होने के तुरंत बाद मैं तीन शब्द कैसे प्राप्त कर सकता हूं?

उत्तर

20

जब आप स्क्रिप्ट अपने आउटपुट में डेटा लिखते हैं तो आप अधिसूचना प्राप्त करने के लिए NSFileHandle की waitForDataInBackgroundAndNotify विधि का उपयोग कर सकते हैं। यह केवल तभी काम करेगा, अगर दुभाषिया तुरंत स्ट्रिंग भेजता है। यदि यह आउटपुट बफर करता है, तो कार्य समाप्त होने के बाद आपको एक ही अधिसूचना मिल जाएगी।

- (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

मैंने कोशिश की, लेकिन यह केवल "पहले" लॉग करता है। कार्यकाल की समाप्ति पर "दूसरा" और "तीसरा" लॉग है ... – akashivskyy

+0

'-receiveData' में अतिरिक्त 'readInBackgroundAndNotify' डालकर इसे हल किया गया। विचार के लिए धन्यवाद! – akashivskyy

+4

मैंने थोड़ी देर के लिए संघर्ष के बाद कोड अपडेट किया। आपको 'readInBackgroundAndNotify'' नहीं, 'WaitForDataInBackgroundAndNotify'' की आवश्यकता है। – citelao

9

संदर्भ के लिए, यहां तेजी से यूघोवाफ्वा का जवाब है।

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!) 
    } 
} 

यदि आपका कार्य पाइप में बहुत सारे आउटपुट का उत्पादन करता है तो यह निर्माण आवश्यक होगा। बस pipe.fileHandleForReading.readDataToEndOfFile() पर कॉल नहीं किया जाएगा क्योंकि कार्य पाइप को खाली करने की प्रतीक्षा कर रहा है ताकि यह आपके डेटा को डेटा के अंत तक प्रतीक्षा कर रहा हो और अधिक लिख सके। इस प्रकार, आपका कार्यक्रम लटका होगा। यह अधिसूचना और पर्यवेक्षक निर्माण पाइप को असीमित रूप से पढ़ने की अनुमति देता है और इस प्रकार उपरोक्त स्टेलेमेट को रोकता है।

संबंधित मुद्दे