cocoa - 如何使用确定的 NSProgressIndicator 来检查 NSTask 的进度? - cocoa

标签 cocoa nstask nsprogressindicator

我所拥有的是 NSTask 运行一个很长的预制 shell 脚本,我希望 NSProgressIndicator 检查完成了多少。我尝试了很多事情,但似乎无法让它发挥作用。如果进度条不确定,我知道如何使用它,但我希望它随着任务的进行而加载。

这是我运行脚本的方式:

- (IBAction)pressButton:(id)sender {
    NSTask *task = [[NSTask alloc] init];
    [task setLaunchPath:@"/bin/sh"];
    [task setArguments:[NSArray arrayWithObjects:[[NSBundle mainBundle] pathForResource:@"script" ofType:@"sh"], nil]];
    [task launch];
}

我需要放置一个进度条,在任务发生时检查任务的进度并进行相应更新。

最佳答案

这是运行 unix 脚本的异步 NSTask 的示例。在 Unix 脚本中,有 echo 命令将当前状态发送回标准错误,如下所示:

回显“工作”>&2

这由通知中心处理并发送到显示器。

要更新确定的进度条,只需发送状态更新(例如“25.0”“26.0”)并转换为 float 并发送到进度栏。

注意:经过大量实验并使用本网站和其他引用文献中的许多技巧,我得到了这个工作。所以我希望它对你有帮助。

以下是声明:

NSTask *unixTask;
NSPipe *unixStandardOutputPipe;
NSPipe *unixStandardErrorPipe;
NSPipe *unixStandardInputPipe;
NSFileHandle *fhOutput;
NSFileHandle *fhError;
NSData *standardOutputData;
NSData *standardErrorData;

以下是主要程序模块:

    - (IBAction)buttonLaunchProgram:(id)sender {

    [_unixTaskStdOutput setString:@"" ];
    [_unixProgressUpdate setStringValue:@""];
    [_unixProgressBar startAnimation:sender];

    [self runCommand];
}
- (void)runCommand {

    //setup system pipes and filehandles to process output data
    unixStandardOutputPipe = [[NSPipe alloc] init];
    unixStandardErrorPipe =  [[NSPipe alloc] init];

    fhOutput = [unixStandardOutputPipe fileHandleForReading];
    fhError =  [unixStandardErrorPipe fileHandleForReading];

    //setup notification alerts
    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];

    [nc addObserver:self selector:@selector(notifiedForStdOutput:) name:NSFileHandleReadCompletionNotification object:fhOutput];
    [nc addObserver:self selector:@selector(notifiedForStdError:)  name:NSFileHandleReadCompletionNotification object:fhError];
    [nc addObserver:self selector:@selector(notifiedForComplete:)  name:NSTaskDidTerminateNotification object:unixTask];

    NSMutableArray *commandLine = [NSMutableArray new];
    [commandLine addObject:@"-c"];
    [commandLine addObject:@"/usr/bin/kpu -ca"]; //put your script here

    unixTask = [[NSTask alloc] init];
    [unixTask setLaunchPath:@"/bin/bash"];
    [unixTask setArguments:commandLine];
    [unixTask setStandardOutput:unixStandardOutputPipe];
    [unixTask setStandardError:unixStandardErrorPipe];
    [unixTask setStandardInput:[NSPipe pipe]];
    [unixTask launch];

    //note we are calling the file handle not the pipe
    [fhOutput readInBackgroundAndNotify];
    [fhError readInBackgroundAndNotify];
}
-(void) notifiedForStdOutput: (NSNotification *)notified
{

    NSData * data = [[notified userInfo] valueForKey:NSFileHandleNotificationDataItem];
    NSLog(@"standard data ready %ld bytes",data.length);

    if ([data length]){

        NSString * outputString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];  
        NSTextStorage *ts = [_unixTaskStdOutput textStorage];
        [ts replaceCharactersInRange:NSMakeRange([ts length], 0)
                          withString:outputString];
    }

    if (unixTask != nil) {

        [fhOutput readInBackgroundAndNotify];
    }

}
-(void) notifiedForStdError: (NSNotification *)notified
{

    NSData * data = [[notified userInfo] valueForKey:NSFileHandleNotificationDataItem];
    NSLog(@"standard error ready %ld bytes",data.length);

    if ([data length]) {

        NSString * outputString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];  
        [_unixProgressUpdate setStringValue:outputString];
    }

    if (unixTask != nil) {

        [fhError readInBackgroundAndNotify];
    }

}
-(void) notifiedForComplete:(NSNotification *)anotification {

    NSLog(@"task completed or was stopped with exit code %d",[unixTask terminationStatus]);
    unixTask = nil;

    [_unixProgressBar stopAnimation:self];
    [_unixProgressBar viewDidHide];

    if ([unixTask terminationStatus] == 0) {
        [_unixProgressUpdate setStringValue:@"Success"]; 
    }
    else {
        [_unixProgressUpdate setStringValue:@"Terminated with non-zero exit code"];
    }
}
@end

关于cocoa - 如何使用确定的 NSProgressIndicator 来检查 NSTask 的进度? - cocoa ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8889006/

相关文章:

objective-c - 如何扩展 NSProgressIndicator 并增加大小

objective-c - WebKit 框架中的shouldStartLoadWithRequest 等效项?

objective-c - 使用 Objective C 在我的 iPad 应用程序和 PC 之间共享文件

macos - 如何调整复选框标签的基线?

Objective-C:来自 NSTask 的多个 View 和数据

xcode - 在 cocoa 应用程序中以 int 形式检索垃圾箱大小

Swift:判断NSProgressIndicator,异步刷新等待返回

objective-c - 超时在 NSAppleScript 中没有效果

objective-c - 是否可以设置 NSTask 拥有的窗口前面和按键?

objective-c - 不确定的 NSProgressIndicator 不会设置动画