【问题标题】:Cocoa crash from non-existant NSViewController不存在的 NSViewController 导致 Cocoa 崩溃
【发布时间】:2016-08-04 18:40:23
【问题描述】:

在我的 mac 应用程序中,我展示了一个登录窗口(在 NSViewController 中通过 sheet segue)。上面有一个 OK 按钮,当我按下它时,我会拨打网络电话。在网络通话结束时,我做了一些事情,然后关闭工作表。该表确实消失了。

现在回到显示登录窗口的 NSViewController 上,我开始上下滚动 NSTableView。我收到有关未提交的 CATransaction 消息的 CoreAnimation 警告。有时它会导致崩溃,有时则不会。

这是我得到的堆栈跟踪:

CoreAnimation:警告,删除了未提交 CATransaction 的线程;创建者:
0 石英核心 0x00007fff8befe69a _ZN2CA11Transaction4pushEv + 318
1 石英核 0x00007fff8befe19a _ZN2CA11Transaction15ensure_implicitEv + 276
2 QuartzCore 0x00007fff8bf04719 _ZN2CA5Layer13thread_flags_EPNS_11TransactionE + 37
3 石英核 0x00007fff8bf04668 _ZN2CA5Layer4markEPNS_11TransactionEjj + 64
4 石英核心 0x00007fff8bf0612b _ZN2CA5Layer25set_needs_display_in_rectERK6CGRect + 333
5 QuartzCore 0x00007fff8bf05fdc -[CALayer setNeedsDisplayInRect:] + 25
6 AppKit 0x00007fff91aff2e8 _NSBackingLayerSetNeedsDisplayInRect + 319
7 AppKit 0x00007fff91aff1a3 -[_NSBackingLayer setNeedsDisplayInRect:] + 61
8 QuartzCore 0x00007fff8bf05f9d -[CALayer setNeedsDisplay] + 62
9 AppKit 0x00007fff91aff98b -[NSView(NSInternal)_setLayerNeedsDisplayInViewRect:] + 606
10 AppKit 0x00007fff91acd88e NSViewSetNeedsDisplayInRect + 945
11 AppKit 0x00007fff91acd4d6 -[NSView setNeedsDisplayInRect:] + 48
12 AppKit 0x00007fff91acd2ed -[NSView setNeedsDisplay:] + 81
13 AppKit 0x00007fff91e48905 -[NSProgressIndicator setDoubleValue:] + 338
14 数字交通系统 0x0000000100063fba _TFFFC22Digital_Traffic_System19LoginViewControllerP33_5EDE918279C9F0B1F3EE7B966507D60715okButtonPressedFCSo8NSButtonT_U_FGSqPs9AnyObject__T_U_FTSSSi_T_ + 266
15 数字交通系统 0x0000000100064282 _TTRXFo_oSSdSi_dT__XFo_iTSSSi__iT__ + 66

第 14 行显示了来自 LoginViewController 的“okButtonPressed”方法,然后在第 13 行我看到它在谈论我的 NSProgressIndicator 试图设置一个值。在这一点上它甚至不应该存在:(

该方法如下所示:

final class LoginViewController: NSViewController, HasMOC {
    @IBOutlet private weak var progressBar: NSProgressIndicator!

    @IBAction private func okButtonPressed(sender: NSButton) {
        sender.enabled = false

        commitEditing()

        // Webserver uses Alamofire to make async web calls.
        Webserver.sharedInstance.startupData {
            [unowned self] data in

            defer { sender.enabled = true }

            guard let json = data as? [[[String : AnyObject]]] else {
                NSAlert.okWithMessage("Failed to download data from web server.")
                return
            }

            self.progressBar.hidden = false

            DataImporter.importData(json, managedObjectContext: self.managedObjectContext,
                onType: {
                    [weak self] str, max in
                    self?.progressBar.doubleValue = 0
                    self?.progressBar.maxValue = Double(max)
                    self?.progressText.stringValue = str
                }, onEntity:  {
                    [weak self] in
                    self?.progressBar.incrementBy(1)
                }, onComplete: {
                    [weak self] in
                    (NSApplication.sharedApplication().delegate as! AppDelegate).showHideReportMenu()

                    self?.onLoginSuccessful?()

                    self?.dismissController(nil)
            })
        }
}

我在初始块中使用 unowned,因为除非网络调用返回,否则此窗口不会消失。没有按钮可以让它手动消失。

【问题讨论】:

  • 我刚刚在 onType、onEntity 和 onComplete 中添加了打印语句。 onComplete 被调用并且工作表消失。当我开始滚动表格并获取堆栈跟踪时,它不会重新打印这三个消息中的任何一个。

标签: swift cocoa


【解决方案1】:

您的服务回调在非 UI 线程上执行,并且您尝试更新 UI 元素。

您应该将它们移至主队列,即:

NSOperationQueue.mainQueue().addOperationWithBlock {
        [unowned self] in
        //Your code changing UI elements, kicking animations .e.t.c
    }

【讨论】:

  • 谢谢。显然,数据导入器在不同的上下文中运行。
猜你喜欢
  • 2014-11-22
  • 2016-02-21
  • 1970-01-01
  • 2012-07-07
  • 1970-01-01
  • 2013-07-01
  • 2011-03-06
  • 2012-04-06
  • 1970-01-01
相关资源
最近更新 更多