在 NSTask 中设置启动路径时如何捕获错误

How to catch error when setting launchpath in NSTask

我正在尝试 运行 在 mac (10.10) 上使用 swift 2 的命令行工具:

let task = NSTask()
task.launchPath = "/path/to/wrong/binary"
task.launch()

// NSPipe() stuff to catch output

task.waitUntilExit()

// never reached
if (task.terminationStatus != 0){
    NSLog("uh oh")
}

由于路径错误,我的程序死掉了launch path not accessible。但是,我不知道如何捕获此错误。在 task.launch() 周围使用 do { try } catch {} 不起作用,因为它不会抛出异常,查看 terminationStatus 也不起作用,因为它从未达到。

怎么才能抓错launchPath

Apple Swift 版本 2.1.1 (swiftlang-700.1.101.15 clang-700.1.81) 目标:x86_64-apple-darwin14.5.0

不幸的是,没有机会捕获运行时异常。使用 try / catch 你可以从错误中恢复,而不是从运行时异常中恢复。您可以创建自己的异常处理程序,但您仍然无法从中恢复。尝试从 NSTask 中获取一些常见的 shell 并将命令作为参数,然后使用管道将 return os 错误发送给您自己的代码。

import Foundation

let task = Process()
let pipe = Pipe()
task.launchPath = "/bin/bash"
task.arguments = ["-c","unknown"]
task.standardOutput = pipe
task.launch()
let handle = pipe.fileHandleForReading
let data = handle.readDataToEndOfFile()
let dataString = String(data: data, encoding: .utf8)
print(dataString ?? "")

将打印

/bin/bash: unknown: command not found

你不应该抓住它。您的计算机,即您的应用 运行 所在的本地环境,被视为可靠的媒介。因此,NSTask 被设计为期望你提供给它的任何路径都保证存在。这很好,因为人们通常使用 NSTask 来启动标准系统可执行文件(bashdiffrsync 等)。路径错误的崩溃旨在帮助您轻松找到代码中的错误。如果您要启动自己的 custom-built 嵌入应用程序包中的二进制文件,您应该 真的 改用 XPC。

如果您确实需要使用 NSTask 来启动不可靠的路径,那么在创建对象之前,您需要使用 NSFileManager 的 fileExistsAtPath(_:isDirectory:) 手动验证路径并做出相应的反应。如果连 POSIX 权限标志都不可靠(此时,您的应用程序可能存在一些严重的安全问题;如果这是一个消费者应用程序项目,我建议您重新考虑您的设计),您还需要检查文件的 NSFilePosixPermissions 属性以确保它是可执行的。

在 Mac OS X High Sierra 中,launch() 已弃用。 您可以使用 run() 代替:

let process = Process()
// ...

do {
    process.run()
} catch let error as NSError {
    print(error.localizedDescription)
    // ...
}

另请参阅 Apple Dev Docs