在NSMenu打开时出现NSAlert会导致UI冻结

时间:2016-09-21 22:31:49

标签: swift macos cocoa grand-central-dispatch nsmenu

正如标题所说,当我的状态栏菜单打开并且从另一个线程触发NSAlert时,UI会冻结。

大概这是因为两个东西都在主线程上运行。但是因为我正在处理NSAlert和NSMenu,所以我不能 在主线程上运行这些吗?

NSAlert代码

func showWallpaperUpdateErrorAlert(messageText: String, informativeText: String) {
    DispatchQueue.main.async {
        NSApp.activate(ignoringOtherApps: true)

        let updateErrorAlert = NSAlert()
        updateErrorAlert.messageText = messageText
        updateErrorAlert.informativeText = informativeText
        updateErrorAlert.addButton(withTitle: "OK")
        updateErrorAlert.runModal()
    }
}

NSMenu代码

func createStatusBarMenu() {
    // Status bar icon
    guard let icon = NSImage(named: "iconFrame44")
        else { NSLog("Error setting status bar icon image."); return }
    icon.isTemplate = true
    statusBarItem.image = icon

    // Create Submenu items
    let viewOnRedditMenuItem = NSMenuItem(title: "View on Reddit...", action: #selector(viewOnRedditAction), keyEquivalent: "")
    viewOnRedditMenuItem.target = self

    let saveThisImageMenuItem = NSMenuItem(title: "Save This Image...", action: #selector(saveThisImageAction), keyEquivalent: "")
    saveThisImageMenuItem.target = self

    // Add to title submenu
    let titleSubmenu = NSMenu(title: "")
    titleSubmenu.addItem(descriptionMenuItem)
    titleSubmenu.addItem(NSMenuItem.separator())
    titleSubmenu.addItem(viewOnRedditMenuItem)
    titleSubmenu.addItem(saveThisImageMenuItem)

    // Create main menu items
    titleMenuItem = NSMenuItem(title: "No Wallpaperer Image", action: nil, keyEquivalent: "")
    titleMenuItem.submenu = titleSubmenu
    titleMenuItem.isEnabled = false
    getNewWallpaperMenuItem = NSMenuItem(title: "Update Now", action: #selector(getNewWallpaperAction), keyEquivalent: "")
    getNewWallpaperMenuItem.target = self

    let preferencesMenuItem = NSMenuItem(title: "Preferences...", action: #selector(preferencesAction), keyEquivalent: "")
    preferencesMenuItem.target = self

    let quitMenuItem = NSMenuItem(title: "Quit Wallpaperer", action: #selector(quitAction), keyEquivalent: "")
    quitMenuItem.target = self

    // Add to main menu
    let statusBarMenu = NSMenu(title: "")
    statusBarMenu.addItem(titleMenuItem)
    statusBarMenu.addItem(NSMenuItem.separator())
    statusBarMenu.addItem(getNewWallpaperMenuItem)
    statusBarMenu.addItem(NSMenuItem.separator())
    statusBarMenu.addItem(preferencesMenuItem)
    statusBarMenu.addItem(quitMenuItem)

    statusBarItem.menu = statusBarMenu

    statusBarMenu.delegate = self
}

1 个答案:

答案 0 :(得分:1)

在我的情况下,解决方案是在显示警告之前关闭菜单。

我必须访问menu的{​​{1}}媒体资源中的菜单,然后致电cancelTrackingWithoutAnimation()(常规cancelTracking()并不顺利)。无论出于何种原因,我还必须在主线外进行此操作。

func showWallpaperUpdateErrorAlert(messageText: String, informativeText: String) {
    statusBarItem.menu?.cancelTrackingWithoutAnimation() // This is new

    DispatchQueue.main.async {
        NSApp.activate(ignoringOtherApps: true)

        let updateErrorAlert = NSAlert()
        updateErrorAlert.messageText = messageText
        updateErrorAlert.informativeText = informativeText
        updateErrorAlert.addButton(withTitle: "OK")
        updateErrorAlert.runModal()
    }
}