2011-08-03 34 views
18

Tôi có một tập lệnh PHP có lệnh mutliple sleep(). Tôi muốn thực hiện nó trong đơn đăng ký của tôi với NSTask. Kịch bản của tôi trông như thế này:Đầu ra thời gian thực của NSTask

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

tôi có thể thực hiện nhiệm vụ của tôi không đồng bộ sử dụng thông báo:

- (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); 
} 

đầu ra của tôi là (sau 2 giây, tất nhiên):

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

Câu hỏi của tôi là: làm thế nào tôi có thể nhận được ba từ ngay sau khi chúng được in?

Trả lời

20

Bạn có thể sử dụng phương pháp waitForDataInBackgroundAndNotify của NSFileHandle để nhận thông báo khi tập lệnh ghi dữ liệu vào đầu ra của nó. Điều này sẽ chỉ hoạt động, tuy nhiên, nếu thông dịch viên gửi các chuỗi ngay lập tức. Nếu nó đệm đầu ra, bạn sẽ nhận được một thông báo duy nhất sau khi thoát khỏi tác vụ.

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

Tôi đã thử điều đó nhưng chỉ ghi nhật ký "đầu tiên". "second" và "third" được ghi lại trên chấm dứt tác vụ ... – akashivskyy

+0

Giải quyết nó bằng cách đặt thêm 'readInBackgroundAndNotify' vào' -receiveData'. Cảm ơn ý tưởng! – akashivskyy

+4

Tôi đã cập nhật mã sau khi đấu tranh một thời gian. Bạn cần một 'waitForDataInBackgroundAndNotify' khác chứ không phải 'readInBackgroundAndNotify'. – citelao

9

Để tham khảo, dưới đây là câu trả lời của ughoavgfhw.

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

Cấu trúc này sẽ cần thiết nếu công việc của bạn tạo ra nhiều đầu ra vào đường ống. Đơn giản chỉ cần gọi pipe.fileHandleForReading.readDataToEndOfFile() sẽ không hoạt động bởi vì nhiệm vụ đang chờ đường ống được làm trống để nó có thể viết nhiều hơn trong khi chương trình của bạn đang chờ kết thúc dữ liệu. Vì vậy, chương trình của bạn sẽ treo. Cấu trúc thông báo và quan sát này cho phép đường ống được đọc không đồng bộ và do đó ngăn chặn sự bế tắc nói trên.

Các vấn đề liên quan