iOS 应用程序或 Playground 中的流程是否始终未解决?

Is Process always unresolved in iOS app or Playground?

在 iOS 应用程序中,我想使用一个文件,该文件使用 Process 具有以下功能:

public func system(_ body: String) throws {
    if #available(macOS 10.0, *) {
        let process = Process()

        ...

    } else {
        fatalError()
    }
}

然后,即使我应用了 Availability Condition 并且我没有调用这个函数,我还是得到了一个休闲错误: 使用未解析的标识符 'Process'.

我在 Playground 中尝试了类似的代码,但我得到了同样的错误。

我了解到我们不能通过这个问题以常规方式在 iOS 应用程序中使用 Process:How to execute terminal commands in Swift 4? ,我有一个解决方案,我通过使用平台将这些代码与文件分开。但如果可以的话,我想使用这个单一文件。

请为我的理想提供另一种解决方案。

if #available() 对 OS 版本执行 运行时检查

if #available(macOS 10.0, *)

如果代码在 macOS 10.0 或更高版本上为 运行,则计算结果为 true 在 iOS/tvOS/watchOS 上 OS 至少是最低部署目标。

你要的是条件编译,取决于平台:

#if os(macOS)
let process = Process()
#else
// ...
#endif

即使你已经解决了这个问题,只是为了让你知道,我想告诉你实际上,Process()(或 Swift 3.0 或更高版本中的 CommandLine())是可用于 iOS,但您需要使用 custom Objective-C header file 来创建对象 Process()/CommandLine(),或者更确切地说 NSTask(),以及它需要的一切。

然后,为了将此代码与 Swift 一起使用,您需要创建一个 Bridging-Header,您需要在其中导入 NSTask.h 文件接触 Swift 并能够在您的 Swift 代码中使用它。

完成后,使用 NSTask() 而不是 Process():

let process = NSTask() /* or NSTask.init() */

或者只要您想 运行 一个任务就在您的代码中使用以下函数:

func task(launchPath: String, arguments: String...) -> NSString {
    let task = NSTask.init()
    task?.setLaunchPath(launchPath)
    task?.arguments = arguments

    // Create a Pipe and make the task
    // put all the output there
    let pipe = Pipe()
    task?.standardOutput = pipe

    // Launch the task
    task?.launch()
    task?.waitUntilExit()

    // Get the data
    let data = pipe.fileHandleForReading.readDataToEndOfFile()
    let output = NSString(data: data, encoding: String.Encoding.utf8.rawValue)

    return output!
}

如您所见,在这种情况下,NSTask() 等同于 Process()

并这样称呼它:

task(launchPath: "/usr/bin/echo", arguments: "Hello World")

这也将 return 值,因此您甚至可以通过以下方式显示它:

print(task(launchPath: "/usr/bin/echo", arguments: "Hello, World!"))

将打印:

~> Hello, World!

为了使其正常工作而不抛出 NSInternalInconsistencyException,您需要将 launchPath 设置为可执行文件的完整路径,而不只是包含它的目录。

您还需要设置所有由 逗号分隔的命令参数.

在 iPad Mini 2 (iOS 12.1 ~> 越狱) 和 iPhone Xr (iOS 12.2 ~> 未越狱).

注意:即使这适用于 non-jailbroken 和越狱设备,您的应用程序将在 AppStore 上被拒绝,正如 @ClausJørgensen 所说:

You're using private APIs, so it'll be rejected on the App Store. Also, Xcode 11 has some new functionality that will trigger a build failure when using certain private APIs.

如果您的应用程序针对越狱的 iOS 设备,并且将被上传到 third-party 商店,如 Cydia、Zebra、Thunderbolt 或 Sileo,那么这将正常工作。

希望对您有所帮助。