2

我试图在我的 Swift 应用程序中检测一个实例是否已经在运行,如果是这样,请避免用户启动另一个实例。我正在使用 NSRunningApplication 类来检测此类行为,但无法使其正常工作。我已经阅读了一些较旧的帖子,并且知道 flock() 是一种较低级别的检测方法,但如果可能的话,我更愿意“以 Swift 的方式进行操作”。这是代码片段:

func applicationDidFinishLaunching(_ aNotification: Notification) {
    // Check if app has already been launched. If so, alert user and terminate the new session
    let bundleID = Bundle.main.bundleIdentifier!

    if NSRunningApplication.runningApplications(withBundleIdentifier: bundleID).count > 1 {
        // warn and terminate
        NSApp.terminate(nil)
    }

    // keep going and finish launching the app
    ...
}

无论我尝试打开多少个会话,返回的计数似乎始终为 1。知道出了什么问题,还是我没有在正确的地方调用此检查?

此外,我的应用程序还允许用户双击具有我定义的文件扩展名的文件来启动应用程序。我假设如果我可以使上述工作,那么它也应该适用于这种情况吗?

更新:

在使用 Activity Monitor 查看我的应用程序的启动行为后,我想我已经确定了观察到的行为的来源。

完全披露,我的应用程序创建了一个新进程来启动控制台应用程序,并将等待该进程完成并终止。更新了以下代码片段:

func applicationDidFinishLaunching(_ aNotification: Notification) {
    // Check if app has already been launched. If so, alert user and terminate the new session
    let bundleID = Bundle.main.bundleIdentifier!

    let num_instances = NSRunningApplication.runningApplications(withBundleIdentifier: bundleID).count

    // Debug dialog box to see instances count
    let alert = NSAlert()
    alert.messageText = "msg"
    alert.informativeText = "num instances running: \(num_instances)"
    alert.alertStyle = NSAlert.Style.critical
    alert.addButton(withTitle: "OK")
    alert.runModal()

    if num_instances > 1 {
        // warn and terminate
        NSApp.terminate(nil)
    }

    // keep going and finish launching the app
    let task = Process()
    task.launchPath = "myConsoleApp"
    task.launch()
    task.waitUntilExit()
    let status = task.terminationStatus

    if status == 0 {
        // Done with the console app, exit
        ...
    } else {
        // something's wrong; report to user
        ...
    }
 }

现在,当应用程序首次启动时,最初创建了两个进程:mySwiftApp 和 myConsoleApp。但是,由于调试对话框的存在,mySwiftApp 进程会在 myConsoleApp 启动后终止。结果,mySwiftApp 的实例计数现在为 0。因此,后续启动 mySwiftApp 将成功,现在系统上运行了两个 myConsoleApp 进程。我不清楚为什么警报框的存在会终止 mySwiftApp 进程,但我怀疑它会向我的应用程序发送终止信号并更改其终止状态。

如果调试对话框不存在,由于 waitUnitlExit() 设置,任何启动第二个实例的尝试都不会被看到,并且基本上会掉到地上。虽然这是“期望的”行为,因为无法启动第二个实例,但最好有办法通知用户。

知道这样做的最佳方法是什么吗?

4

0 回答 0