【问题标题】:Open File Dialog crashes in Swift在 Swift 中打开文件对话框崩溃
【发布时间】:2014-10-17 21:16:44
【问题描述】:

我想使用 NSFilemanager 中的打开文件对话框,但我的代码有时会崩溃,有时会正常工作,但我不知道为什么。有时它可以 100% 工作,有时窗口是空的,有时对话框后面的背景会显示在窗口中。发生崩溃时,Xcode 中会显示“signal:SIGABRT”。

func openfiledlg (title: String, message: String) -> String
{
    var myFiledialog: NSOpenPanel = NSOpenPanel()

    myFiledialog.prompt = "Öffnen"
    myFiledialog.worksWhenModal = true
    myFiledialog.allowsMultipleSelection = false
    myFiledialog.canChooseDirectories = false
    myFiledialog.resolvesAliases = true
    myFiledialog.title = title
    myFiledialog.message = message
    myFiledialog.runModal()
    var chosenfile = myFiledialog.URL
    if (chosenfile != nil)
    {
        var TheFile = chosenfile.absoluteString!
        return (TheFile)
    }
    else
    {
        return ("")
    }
}

我做错了什么?为什么会崩溃?

应用程序不在主线程上运行。我总是打开一个新线程,它运行我的程序。主线程仅处理来自 SpriteKit 的屏幕更新,我将其用于我的程序。

我刚刚构建了一个新的基于 Cocoa 的应用程序,并让函数在主线程中运行,然后它就可以工作了。当我在 Cocoa-App 中启动线程时,它会像在 SpriteKit 环境中一样崩溃。

我需要在 Sprite-Kit 环境中启动一个新线程,因为如果我直接从 AppDelegate 启动我的主程序,更新将不会完成。主程序一直运行到整个 SpriteKit 退出,所以我没有机会在主线程中完成我的工作。

崩溃发生在 runModal() 的行中,然后在“NSSavePanel._spAuxiliaryStorage”中:

0x7fff84dfec20:  movq   -0x10c18197(%rip), %rsi   ; "_refreshDelegateOptions"
0x7fff84dfec27:  movq   %rbx, %rdi
0x7fff84dfec2a:  callq  *%r15
0x7fff84dfec2d:  movq   -0x10c17ed4(%rip), %rsi   ; "_loadPreviousModeAndLayout"
0x7fff84dfec34:  movq   %rbx, %rdi
0x7fff84dfec37:  callq  *%r15
0x7fff84dfec3a:  movq   -0x10b57079(%rip), %r12   ; NSSavePanel._spAuxiliaryStorage <--- Thread 7: signal SIGABRT
0x7fff84dfec41:  movq   (%rbx,%r12), %rax
0x7fff84dfec45:  movq   -0x10b5716c(%rip), %rcx   ; NSSavePanelAuxiliary._clientSetADirectory
0x7fff84dfec4c:  movb   (%rax,%rcx), %al
0x7fff84dfec4f:  shrb   $0x2, %al
0x7fff84dfec52:  andb   $0x1, %al
0x7fff84dfec54:  xorb   $0x1, %al
0x7fff84dfec56:  movzbl %al, %ecx
0x7fff84dfec59:  movq   -0x10c18310(%rip), %rsi   ; "_configureForDirectory:forceDefault:"
0x7fff84dfec60:  movq   %rbx, %rdi
0x7fff84dfec63:  xorl   %edx, %edx
0x7fff84dfec65:  callq  *%r15
0x7fff84dfec68:  movq   -0x10c2d767(%rip), %rsi   ; "drain"
0x7fff84dfec6f:  movq   %r14, %rdi
0x7fff84dfec72:  callq  *%r15
0x7fff84dfec75:  movq   (%rbx,%r12), %rsi

在终端窗口中显示:

CocoaTest(54483,0x106f78000) malloc: *** error for object 0x60800017efc0: Heap corruption detected, free list canary is damaged

知道如何在不在主线程中执行此问题的情况下解决此问题吗?

【问题讨论】:

  • 它在哪一行崩溃?你能添加一个堆栈跟踪吗?你确定在主线程上调用它吗?您的应用是沙箱和/或签名的吗?

标签: swift xcode nsfilemanager nsopenpanel


【解决方案1】:

用户界面(UI)调用的限制,不是线程保存,可以解决,当您使用以下代码时,它在主线程中异步执行一个命令块:

dispatch_async(dispatch_get_main_queue())
{
    // This commands are executed ansychronously
}

因此您必须为每个内置函数编写自己的函数,这不是像这样的线程保存(打开文件对话框的示例):

func not (b: Bool) -> Bool
{
    return (!b)
}

func suspendprocess (t: Double)
{
    var secs: Int = Int(abs(t))
    var nanosecs: Int = Int(frac(abs(t)) * 1000000000)
    var time = timespec(tv_sec: secs, tv_nsec: nanosecs)
    let result = nanosleep(&time, nil)
}

func openfiledialog (windowTitle: String, message: String, filetypelist: String) -> String
{
    var path: String = ""
    var finished: Bool = false

    suspendprocess (0.02) // Wait 20 ms., enough time to do screen updates regarding to the background job, which calls this function
    dispatch_async(dispatch_get_main_queue())
    {
        var myFiledialog: NSOpenPanel = NSOpenPanel()
        var fileTypeArray: [String] = filetypelist.componentsSeparatedByString(",")

        myFiledialog.prompt = "Open"
        myFiledialog.worksWhenModal = true
        myFiledialog.allowsMultipleSelection = false
        myFiledialog.canChooseDirectories = false
        myFiledialog.resolvesAliases = true
        myFiledialog.title = windowTitle
        myFiledialog.message = message
        myFiledialog.allowedFileTypes = fileTypeArray

        let void = myFiledialog.runModal()

        var chosenfile = myFiledialog.URL // Pathname of the file

        if (chosenfile != nil)
        {
            path = chosenfile!.absoluteString!
        }
        finished = true
    }

    while not(finished)
    {
        suspendprocess (0.001) // Wait 1 ms., loop until main thread finished
    }

    return (path)
}

请注意,该块是异步调用的,这意味着您必须检查该块是否已被处理并且是否已完成。所以我添加了一个布尔变量“finsihed”,它显示,当块到达它的末尾。没有这个,你不会得到路径名,而只会得到一个空字符串。

如果你有兴趣,我也会发布我的 savefiledialog-function。如果有请留言。

【讨论】:

  • 究竟什么是“压裂”?目前,Swift 1.2 无法解析该标识符。
  • frac 给出实数的小数部分。这是“var - Int(var)”。我目前使用 Xcode 6.3.1,它可以编译 wll。您必须导入 Cocoa,也许这是您的问题。 Frac 是标准数学的一部分,这个函数很久没有改变了。
【解决方案2】:

大多数用户界面 (UI) 调用不是线程保存的,这意味着它们只能在主线程中没有崩溃和异常行为的情况下工作。

这也是 NSOpenPanel 调用的问题。从主线程调用时一切正常。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多