- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想使用 NSTask 执行命令,并能够在模式窗口中查看进度。例如,如果我执行“ls -R/”,我希望看到 block 出现在 NSTextView 中。
我想出了以下内容,除了更新部分之外,一切正常。任务被执行(使用旋转的 beachbal),完成后我看到结果出现在 TextView 中。
@interface ICA_RunWindowController ()
@property (strong) IBOutlet NSTextView* textResult;
@property (strong) IBOutlet NSButton* buttonAbort;
@property (strong) IBOutlet NSButton* buttonOK;
- (IBAction) doOK:(id) sender;
- (IBAction) doAbort:(id) sender;
@end
@implementation ICA_RunWindowController {
NSTask * executionTask;
id taskObserver;
NSFileHandle * errorFile;
id errorObserver;
NSFileHandle * outputFile;
id outputObserver;
}
@synthesize textResult,buttonAbort,buttonOK;
- (IBAction)doOK:(id)sender {
[[self window] close];
[NSApp stopModal];
}
- (IBAction)doAbort:(id)sender {
[executionTask terminate];
}
- (void) taskCompleted {
NSLog(@"Task completed");
[[NSNotificationCenter defaultCenter] removeObserver:taskObserver];
[[NSNotificationCenter defaultCenter] removeObserver:errorObserver];
[[NSNotificationCenter defaultCenter] removeObserver:outputObserver];
[self outputAvailable];
[self errorAvailable];
executionTask = nil;
[buttonAbort setEnabled:NO];
[buttonOK setEnabled:YES];
}
- (void) appendText:(NSString *) text inColor:(NSColor *) textColor {
NSDictionary * makeUp = [NSDictionary dictionaryWithObject:textColor forKey:NSForegroundColorAttributeName];
NSAttributedString * extraText = [[NSAttributedString alloc] initWithString:text attributes:makeUp];
[textResult setEditable:YES];
[textResult setSelectedRange:NSMakeRange([[textResult textStorage] length], 0)];
[textResult insertText:extraText];
[textResult setEditable:NO];
[textResult display];
}
- (void) outputAvailable {
NSData * someData = [outputFile readDataToEndOfFile];
if ([someData length] > 0) {
NSLog(@"output Available");
NSString * someText = [[NSString alloc] initWithData:someData encoding:NSUTF8StringEncoding];
[self appendText:someText inColor:[NSColor blackColor]];
}
}
- (void) errorAvailable {
NSData * someData = [errorFile readDataToEndOfFile];
if ([someData length] > 0) {
NSLog(@"Error Available");
NSString * someText = [[NSString alloc] initWithData:someData encoding:NSUTF8StringEncoding];
[self appendText:someText inColor:[NSColor redColor]];
}
}
- (void) runCommand:(NSString *) command {
// make sure all views are initialized
[self showWindow:[self window]];
// some convience vars
NSArray * runLoopModes = @[NSDefaultRunLoopMode, NSRunLoopCommonModes];
NSNotificationCenter * defCenter = [NSNotificationCenter defaultCenter];
// create an task
executionTask = [[NSTask alloc] init];
// fill the parameters for the task
[executionTask setLaunchPath:@"/bin/sh"];
[executionTask setArguments:@[@"-c",command]];
// create an observer for Termination
taskObserver = [defCenter addObserverForName:NSTaskDidTerminateNotification
object:executionTask
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note)
{
[self taskCompleted];
}
];
// Create a pipe and a filehandle for reading errors
NSPipe * error = [[NSPipe alloc] init];
[executionTask setStandardError:error];
errorFile = [error fileHandleForReading];
errorObserver = [defCenter addObserverForName:NSFileHandleDataAvailableNotification
object:errorFile
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note)
{
[self errorAvailable];
[errorFile waitForDataInBackgroundAndNotifyForModes:runLoopModes];
}
];
[errorFile waitForDataInBackgroundAndNotifyForModes:runLoopModes];
// Create a pipe and a filehandle for reading output
NSPipe * output = [[NSPipe alloc] init];
[executionTask setStandardOutput:output];
outputFile = [output fileHandleForReading];
outputObserver = [defCenter addObserverForName:NSFileHandleDataAvailableNotification
object:outputFile
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note)
{
[self outputAvailable];
[outputFile waitForDataInBackgroundAndNotifyForModes:runLoopModes];
}
];
[outputFile waitForDataInBackgroundAndNotifyForModes:runLoopModes];
// start task
[executionTask launch];
// show our window as modal
[NSApp runModalForWindow:[self window]];
}
我的问题:任务运行时是否可以更新输出?如果是的话,我怎样才能实现这一目标?
最佳答案
模态窗口在 NSModalPanelRunLoopMode
中运行运行循环,因此您需要将其添加到 runLoopModes
中。
你不应该得到旋转的沙滩球。原因是您在 -outputAvailable
和 -errorAvailable
方法中调用 -readDataToEndOfFile
。鉴于您使用的是 -waitForDataInBackgroundAndNotifyForModes:
,您可以使用 -availableData
方法来获取可用数据而不阻塞。
或者,您可以使用 -readInBackgroundAndNotifyForModes:
,监视 NSFileHandleReadCompletionNotification
通知,并在处理程序中使用 [[ 从通知对象获取数据注意 userInfo] objectForKey:NSFileHandleNotificationDataItem]
。换句话说,让 NSFileHandle
为您完成读取数据的工作。
无论哪种方式,一旦您获得文件结束指示符(空的 NSData
),您就不应该重新发出 ...InBackgroundAndNotifyForModes:
称呼。如果这样做,您将忙于旋转,因为它会一遍又一遍地向您提供相同的文件结束指示符。
不需要手动-显示
您的 TextView 。一旦修复了导致色轮光标旋转的阻塞调用,这也将允许正常的窗口更新自动发生。
关于macos - 如何在后台运行 NSTask 并在运行时在模态 NSWindow 中显示结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24961725/
我是一名优秀的程序员,十分优秀!