在 mac 中发生锁定时如何以编程方式 运行 执行任务

how to programatically run a task when a logout occurs in mac

当 Mac

中发生注销事件时,我正在尝试 运行 shell 命令
 logoutNotificationCenter.notificationCenter.addObserver(self, selector: #selector(AppDelegate.logOut),name:NSWorkspace.willPowerOffNotification, object: nil)

内部注销我正在使用 运行 shell 命令

func shell(path:String,commandargs: [String]) -> Bool
    {
        var ret : Bool = false
        
        let task = Process()
        task.launchPath = path
        task.arguments = commandargs
        task.launch()
        task.waitUntilExit()
        
        if !task.isRunning {
            let status = task.terminationStatus
            if status == 0 {
                ret = true
            } else {
                ret = false
            }
        }
        return ret
    }

虽然我的通知是由 shell 触发的,但不是 运行 ,甚至在此之前我的系统就已经关闭了。有没有一种方法可以在我的 shell 命令执行之前停止注销。

我再次阅读了您的问题,问题是 applicationShouldTerminate(_:) 在 发送 NSWorkspace.willPowerOffNotification 之前被调用 。这意味着你不知道发生了什么。

然后我意识到我们得到了kAEQuitReason。很好奇它是否仍然有效并且确实有效。下面的例子。以适合您需要的方式修改它。

import Cocoa

@main
class AppDelegate: NSObject, NSApplicationDelegate {
    @IBOutlet var window: NSWindow!
    
    private var logoutTaskLaunched = false
    
    private func launchLogoutTask() {
        assert(!logoutTaskLaunched, "Logout task was already launched")
        
        let task = Process()
        task.executableURL = URL(fileURLWithPath: "/bin/sleep")
        task.arguments = ["5"]
        task.terminationHandler = { task in
            if task.terminationStatus == 0 {
                print("Logout task - success")
                DispatchQueue.main.async {
                    NSApp.reply(toApplicationShouldTerminate: true)
                }
            } else {
                print("Logout task - failed")
                DispatchQueue.main.async { [weak self] in
                    NSApp.reply(toApplicationShouldTerminate: false)
                    self?.logoutTaskLaunched = false
                }
            }
        }
        do {
            try task.run()
            logoutTaskLaunched = true
            print("Logout task - Sleeping for 5s")
        }
        catch {
            print("Logout task - failed to launch task: \(error)")
            NSApp.reply(toApplicationShouldTerminate: false)
        }
    }
    
    func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply {
        let reason = NSAppleEventManager.shared()
            .currentAppleEvent?
            .attributeDescriptor(forKeyword: kAEQuitReason)
        
        switch reason?.enumCodeValue {
        case kAELogOut, kAEReallyLogOut:
            print("Logout")
            if !logoutTaskLaunched {
                launchLogoutTask()
            }
            return .terminateLater
            
        case kAERestart, kAEShowRestartDialog:
            print("Restart")
            return .terminateNow
            
        case kAEShutDown, kAEShowShutdownDialog:
            print("Shutdown")
            return .terminateNow
            
        case 0:
            // `enumCodeValue` docs:
            //
            //    The contents of the descriptor, as an enumeration type,
            //    or 0 if an error occurs.
            print("We don't know")
            return .terminateNow
            
        default:
            print("Cmd-Q, Quit menu item, ...")
            return .terminateNow
        }
    }
}