xcode - 代码会跳过直到 NSTask 完成

标签 xcode macos cocoa

我正在使用 Cocoa 为 Mac 创建一个小型碎纸机应用程序,可以安全地删除文件。每次我的 NSTask 接收数据来更新一些 UI 元素时,我都会运行代码。问题是有些事情(文件保留标签、将进度条设置为 0、将窗口置于前台)在 NSTask 完成之前不起作用。当文件被拖放到我的窗口中时,此代码将被激活。

- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender {
    int filesRemain = 0;

    NSPasteboard *pboard = [sender draggingPasteboard];

    NSArray *files = [pboard propertyListForType:NSFilenamesPboardType];
    NSMutableArray *args = [[NSMutableArray alloc] init];
    [args addObject:@"-rfv"];
    for(NSString * myStr in files) {
        [args addObject:myStr];
        filesRemain ++;
    }
    NSTask *task = [[NSTask alloc] init];

    task.launchPath = @"/usr/bin/srm";

    task.arguments  = args;

    NSPipe *pipe = [NSPipe pipe];
    [task setStandardOutput: pipe];
    [task launch];
    NSLog(@"task launched");
    while ([task isRunning])
    {
        NSData* data = [[pipe fileHandleForReading] availableData];
        NSString *string;
        string = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
        if ([string hasSuffix:@"%"]) {
            NSString *numberString;
            NSScanner *scanner = [NSScanner scannerWithString:string];
            NSCharacterSet *numbers = [NSCharacterSet characterSetWithCharactersInString:@"0123456789"];
            [scanner scanUpToCharactersFromSet:numbers intoString:NULL];
            [scanner scanCharactersFromSet:numbers intoString:&numberString];
            int number = [numberString intValue];
            [progIndicator setDoubleValue:number];
            [progText setStringValue:[NSString stringWithFormat:@"%d Files Remaining", filesRemain]];
        } else if (!([string rangeOfString:@"done"].location == NSNotFound)) {
            filesRemain --;
            [progIndicator setDoubleValue:100];
            if (filesRemain == 0) {
                NSLog(@"process completed");
                [dropWindow setAlphaValue:1];
                [progressView setAlphaValue:0];
            } else {
                [progIndicator setDoubleValue:0];
            }
        }
    }
    return YES;
}

有什么办法可以防止这段代码被跳过吗?谢谢您的解答!

最佳答案

此代码存在一些问题:

⑴ 您在 while() 循环中阻塞了主线程,因此在完成之前不会显示任何内容,并且应用程序将锁定并且用户将无法输入内容。您可以通过每次添加调用 -display 有问题的 View 来解决此问题,但请不要这样做,因为还有其他问题,例如

⑵ 您将按照循环执行的速度从任务中轮询数据,两次尝试之间没有任何延迟,因此您绝对会消耗用户的电池。 CPU 非常快,它每秒可以处理数十亿条指令,因此这个循环将开始快速旋转,比任务产生输出的速度快得多,并且它将疯狂地更新所有进度表。

⑶ 在请求 availableData 之前,您不会检查是否有可用数据,因此您的应用在等待任务完成时可能会无限期暂停。

<小时/>

有多种方法可以解决这些问题。最现代、最好的方法是将 fileHandle 的 readabilityHandler 设置为一个 block ,该 block 在主线程上安排 UI 更新,然后立即从上面的方法返回,以便主运行循环重新获得控制权并显示发生。

请注意(从文档来看)您的 readabilityHandler 似乎将从任意线程调用,因此您不想修改任何不 protected 实例变量或直接从中进行任何 UI 调用。您可以做的是使用它来安排主线程上的 UI 更新,如下所示:

NSPipe *pipe = [NSPipe pipe];
[task setStandardOutput: pipe];
[task launch];
pipe.fileHandleForReading.readabilityHandler = ^{
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        NSString *const string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        // ...
        // update UI code
        // ...
    };
};

关于xcode - 代码会跳过直到 NSTask 完成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21391936/

相关文章:

swift - 在 Swift 中添加 ValueTransformer

ios - 核心音频内存问题

cocoa - Mac应用程序默认工作目录

objective-c - OSX 10.7 中的版本

macos - 检查像素颜色并触发 bash 脚本

c - JNI 库中 OS/X 上的指针截断为 'realloc()'

objective-c - 拖放不适用于 NSBox 的子类

xcode - Xcode 中的 Vim 键绑定(bind)?

iOS - 在 Storyboard中管理代码合并的最佳实践

xcode - 更新到 7.1 后无法在我的 iPhone 上测试应用程序