2012-04-01 51 views
1

所以,这是我的代码:异步执行工作不正常

- (void)runCmd:(NSString *)cmd withArgs:(NSArray *)args 
{ 
    NSLog(@"\nRunning ::\n\tCmd : %@\n\tArgs : %@",cmd, args); 
    [theSpinner start]; 
    if (task) 
    { 
     [task interrupt]; 

    } 
    else 
    { 
     task = [[NSTask alloc] init]; 
     [task setLaunchPath:cmd]; 

     [task setArguments:args]; 

     [pipe release]; 

     pipe = [[NSPipe alloc] init]; 
     [task setStandardOutput:pipe]; 

     NSFileHandle* fh = [pipe fileHandleForReading]; 

     NSNotificationCenter* nc; 

     nc = [NSNotificationCenter defaultCenter]; 
     [nc removeObserver:self]; 
     [nc addObserver:self 
       selector:@selector(dataReady:) 
        name:NSFileHandleReadCompletionNotification 
       object:fh]; 
     [nc addObserver:self selector:@selector(dataAvailable:) name:NSFileHandleDataAvailableNotification object:fh]; 
     [nc addObserver:self 
       selector:@selector(taskTerminated:) 
        name:NSTaskDidTerminateNotification 
       object:task]; 

     [task launch]; 
     [fh readInBackgroundAndNotify]; 
    } 
} 

- (void)dataAvailable:(NSNotification*)n 
{ 
    NSLog(@"Data Available : %@",n); 
} 

- (void)dataReady:(NSNotification*)n 
{ 
    NSData* d; 

    d = [[n userInfo] valueForKey:NSFileHandleNotificationDataItem]; 

    NSLog(@"Data Ready : %@",n); 

    if ([d length]) 
    { 
     NSLog(@"Data Ready : %@",[[NSString alloc] initWithData:d encoding:NSUTF8StringEncoding]); 
    } 
} 

- (void) taskTerminated:(NSNotification*)note 
{ 
    NSLog(@"Task Terminated : %@",note); 
    [task release]; 
    task = nil; 
    [theSpinner stop]; 

    NSAlert *alert = [[[NSAlert alloc] init] autorelease]; 
    [alert setMessageText:[NSString stringWithFormat:@"Command finished"]]; 

    [alert runModal]; 
} 

我已经尝试运行的命令(例如PHP解释器在/usr/bin/php)与参数(例如文件被解释php test.php)。

的事情是:

  • 脚本运行正常
  • ,但是我收到一个Data ReadyTask Terminated 通知之前,我已经成功地得到所有的输出。 (我的意思是, 的dataReady:函数获取刚刚
    输出和它的其余部分的第一部分是无处可寻...)

我基本上要被读取,异步,所有输出 - 当命令正在运行时。

任何想法?我究竟做错了什么?

谢谢!

回答

4

您使用readInBackgroundAndNotify安排您的阅读。该方法只读取一个充满数据的缓冲区并通知。您需要在通知方法中再次拨打readInBackgroundAndNotify来阅读更多数据,或者如果您想一次接收所有数据,则需要使用readToEndOfFileInBackgroundAndNotify

+0

绝对正确。 (顺便说一句,顺便说一句,但是非常感谢!-)) – 2012-04-01 15:16:49

1

自10.7以来有一个新API,因此您可以避免使用NSNotifications。

task.standardOutput = [NSPipe pipe]; 
[[task.standardOutput fileHandleForReading] setReadabilityHandler:^(NSFileHandle *file) { 
    NSData *data = [file availableData]; // this will read to EOF, so call only once 
    NSLog(@"Task output! %@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); 

    // if you're collecting the whole output of a task, you may store it on a property 
    [self.taskOutput appendData:data]; 
}]; 

重要:

当任务结束,你必须设置readabilityHandler块零;否则,你会遇到高CPU使用率,因为阅读永远不会停止。

[task setTerminationHandler:^(NSTask *task) { 

    // do your stuff on completion 

    [task.standardOutput fileHandleForReading].readabilityHandler = nil; 
    [task.standardError fileHandleForReading].readabilityHandler = nil; 
}];