Macos 如何在后台运行NSTask,并在运行时在模式窗口中显示结果

Macos 如何在后台运行NSTask,并在运行时在模式窗口中显示结果,macos,cocoa,nswindow,nstask,Macos,Cocoa,Nswindow,Nstask,我希望使用NSTask执行命令,并能够在模式窗口中查看进度。例如,如果执行“ls-R/”,我希望看到块出现在NSTextView中 我提出了以下建议,除更新部分外,一切正常。任务得到执行(使用旋转的海滩),当任务完成时,我看到结果显示在文本视图中 @interface ICA\u RunWindowController() @属性(强)IBMOutlet NSTextView*textResult; @属性(强)IBN按钮*按钮端口; @属性(强)IBNSButton*buttonOK; -(i

我希望使用NSTask执行命令,并能够在模式窗口中查看进度。例如,如果执行“ls-R/”,我希望看到块出现在NSTextView中

我提出了以下建议,除更新部分外,一切正常。任务得到执行(使用旋转的海滩),当任务完成时,我看到结果显示在文本视图中

@interface ICA\u RunWindowController()
@属性(强)IBMOutlet NSTextView*textResult;
@属性(强)IBN按钮*按钮端口;
@属性(强)IBNSButton*buttonOK;
-(iAction)doOK:(id)发送方;
-(iAction)doAbort:(id)发送方;
@结束
@运行窗口控制器的实现{
NSTask*执行任务;
id任务观察者;
NSFileHandle*errorFile;
id错误观察者;
NSFileHandle*输出文件;
id输出观察者;
}
@综合文本结果、按钮栏、按钮栏;
-(iAction)doOK:(id)发送者{
[[自动窗口]关闭];
[NSApp stopModal];
}
-(iAction)doAbort:(id)发送方{
[执行任务终止];
}
-(作废)任务已完成{
NSLog(@“任务已完成”);
[[NSNotificationCenter defaultCenter]removeObserver:taskObserver];
[[NSNotificationCenter defaultCenter]removeObserver:errorObserver];
[[NSNotificationCenter defaultCenter]removeObserver:outputObserver];
[自我输出可用];
[自备];
executionTask=nil;
[按钮端口设置启用:否];
[按钮设置启用:是];
}
-(void)appendText:(NSString*)文本颜色:(NSColor*)文本颜色{
NSDictionary*Component=[NSDictionary Dictionary WithObject:textColor forKey:NSForegroundColorAttributeName];
NSAttributedString*extraText=[[NSAttributedString alloc]initWithString:text属性:化妆];
[文本结果集可编辑:是];
[textResult setSelectedRange:NSMakeRange([textResult textStorage]长度],0)];
[textResult insertText:extraText];
[文本结果集可编辑:否];
[文本结果显示];
}
-(无效)可输出{
NSData*someData=[outputFile readDataToEndOfFile];
如果([someData长度]>0){
NSLog(“输出可用”);
NSString*someText=[[NSString alloc]initWithData:someData编码:NSUTF8StringEncoding];
[self appendText:someText inColor:[NSColor blackColor]];
}
}
-(无效)错误可用{
NSData*someData=[errorFile readDataToEndOfFile];
如果([someData长度]>0){
NSLog(@“错误可用”);
NSString*someText=[[NSString alloc]initWithData:someData编码:NSUTF8StringEncoding];
[self appendText:someText inColor:[NSColor redColor]];
}
}
-(void)runCommand:(NSString*)命令{
//确保所有视图都已初始化
[自显示窗口:[自显示窗口]];
//一些方便车
NSArray*runLoopModes=@[NSDefaultRunLoopMode,NSRunLoopCommonModes];
NSNotificationCenter*defCenter=[NSNotificationCenter defaultCenter];
//创建任务
executionTask=[[NSTask alloc]init];
//填写任务的参数
[ExecutionTaskSetLaunchPath:@/bin/sh];
[executionTask setArguments:@[@“-c”,命令]];
//创建终止的观察者
taskObserver=[defCenter addObserverForName:NSTASKIDTerminateNotification
对象:executionTask
队列:[NSOperationQueue mainQueue]
使用block:^(NSNotification*注释)
{
[自行完成任务];
}
];
//创建用于读取错误的管道和文件句柄
NSPipe*错误=[[NSPipe alloc]init];
[执行任务设置标准错误:错误];
errorFile=[ErrorFileHandleForReading];
errorObserver=[defCenter addObserverForName:NSFileHandleDataAvailableNotification
对象:错误文件
队列:[NSOperationQueue mainQueue]
使用block:^(NSNotification*注释)
{
[自备];
[错误文件waitForDataInBackgroundAndNotifyForModes:runLoopModes];
}
];
[错误文件waitForDataInBackgroundAndNotifyForModes:runLoopModes];
//创建用于读取输出的管道和文件句柄
NSPipe*输出=[[NSPipe alloc]init];
[执行任务设置标准输出:输出];
outputFile=[OutputFileHandleForReading];
outputObserver=[defCenter addObserverForName:NSFileHandleDataAvailableNotification
对象:输出文件
队列:[NSOperationQueue mainQueue]
使用block:^(NSNotification*注释)
{
[自我输出可用];
[outputFile waitForDataInBackgroundAndNotifyForModes:runLoopModes];
}
];
[outputFile waitForDataInBackgroundAndNotifyForModes:runLoopModes];
//启动任务
[执行任务启动];
//将我们的窗口显示为模态
[NSApp runModalForWindow:[自窗口]];
}

我的问题:任务运行时是否可以更新输出?如果是,我该如何实现这一点?

模式窗口在
nsmodalPanelUnloopMode
中运行运行循环,因此您需要将其添加到
运行循环模式中

你不应该得到旋转沙滩球。原因是您正在调用
-outputavaailable
-errorAvailable
方法中的
-readdatatoendofile
。假设您使用的是
-waitForDataInBackgroundAndNotifyForModes:
,那么您将使用
-availableData
方法在不阻塞的情况下获取可用数据

或者,您可以使用
-readInBackgroundAndNotifyForModes:
,监视
NSFileHandleReadCompletionNotification
通知,并在处理程序中使用
[[note userInfo]objectForKey:NSFileHandleNotificationDataItem]
从通知对象获取数据。换句话说,让
NSFileHa