【问题标题】:How to gradually retrieve data from NSTask?如何逐步从 NSTask 中检索数据?
【发布时间】:2010-07-19 20:27:39
【问题描述】:

我正在为命令行工具开发 GUI (Cocoa),以使其更易于人们使用。尽管它是一个 GUI,但我想将输出显示到 NSTextView。问题是输出量很大,并且该工具执行的分析可能需要数小时/数天。

通常,在使用 NSTask 和 NSPipe 时,只有在任务完全完成后才会显示输出(这可能需要很长时间)。我想要做的是将输出拆分并逐渐显示(例如每分钟更新一次)。

到目前为止,我已将数据的处理放在一个单独的线程中:

[NSThread detachNewThreadSelector:@selector(processData:) toTarget:self withObject:raxmlHandle];

- (void)processData:(id)sender {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    NSString *startString = [results string];
    NSString *newString = [[NSString alloc] initWithData:[raxmlHandle readDataToEndOfFile] encoding:NSASCIIStringEncoding];
    [results setString:[startString stringByAppendingString:newString]];
    [startString release];
    [newString release];
    [pool release];
}

这一切对我来说仍然是一种巫术,我不确定如何应对这一挑战。

您有什么建议或建议吗?

谢谢!

【问题讨论】:

    标签: cocoa user-interface macos


    【解决方案1】:

    您需要使用NSFileHandle 提供的通知。

    首先,将自己作为观察者添加到NSFileHandleReadCompletionNotification

    [[NSNotificationCenter defaultCenter] addObserver:self  
                                             selector:@selector(outputReceived:) 
                                                 name:NSFileHandleReadCompletionNotification
                                               object:nil];
    

    然后,准备一个任务,调用管道文件句柄的readInBackgrounAndNotify,启动任务。

    NSTask*task=[[NSTask alloc] init];
    [task setLaunchPath:...];
    
    NSPipe*pipe=[NSPipe pipe];
    [task setStandardOutput:pipe];
    [task setStandardError:pipe];
    
    // this causes the notification to be fired when the data is available
    [[pipe fileHandleForReading] readInBackgroundAndNotify];  
    
    [task launch];
    

    现在,要实际接收数据,您需要定义一个方法

    -(void)outputReceived:(NSNotification*)notification{
        NSFileHandle*fh=[notification object];
        // it might be good to check that this file handle is the one you want to read
        ...
    
        NSData*d=[[aNotification userInfo] objectForKey:@"NSFileHandleNotificationDataItem"];
        ... do something with data ...
    }
    

    您可能想阅读Notification Programming Topics 以了解发生了什么。

    【讨论】:

    • 非常感谢 Yuji 花时间写下你的答案。我要去潜水了!
    • 有谁知道如何更好地控制 NSPipe 的输出大小?换句话说,使用上述方法(Yuji 的方法),数据被大块清除,这使得它对用户不太友好。我正在寻找一种解决方案,其中每一行输出都可以单独显示(更像是终端或控制台工作)。有什么建议吗?
    • 阅读这个 SO 讨论:stackoverflow.com/questions/1000674/turn-off-buffering-in-pipe 问题是发送端的 stdio 在将数据发送到管道时会自动更改其行为。您需要欺骗它以为它正在写入 tty。在 Cocoa 中也应该有一种实现 tty 的方法,但我不知道如何实现。我确定可以在 iTerm 的源代码中找到它,iterm.sourceforge.net。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-29
    • 2018-03-19
    • 1970-01-01
    • 1970-01-01
    • 2021-10-02
    相关资源
    最近更新 更多