【问题标题】:NSAlert appearing while NSMenu is open causes UI to freezeNSMenu 打开时出现 NSAlert 导致 UI 冻结
【发布时间】:2017-01-30 08:27:16
【问题描述】:

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

大概这是因为这两个东西都在主线程上运行。但是由于我正在处理 NSAlert 和 NSMenu,难道我必须在主线程上运行它们吗?

安全警报代码

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
}

【问题讨论】:

  • 您好,您的 OS X 版本是多少?是 os x 10.12 (Sierra) 吗?
  • 是的,我在 Sierra。

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


【解决方案1】:

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

我必须从NSStatusItem 的menu 属性访问菜单并调用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()
    }
}

【讨论】:

    猜你喜欢
    • 2012-08-02
    • 2018-08-12
    • 2018-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多