xcode 打开文件对话框在 Swift 中崩溃
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25473764/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Open File Dialog crashes in Swift
提问by j.s.com
I would like to use the open file dialogs from NSFilemanager but my code crashes sometimes and sometimes works and I do not know why. Sometimes it works 100%, sometimes the window is empty, sometimes the background behind the dialog ist shown in the window. When a craash occurs, "signal:SIGABRT" is shown in Xcode.
我想使用 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 ("")
}
}
What have I done wrong? Why does it crash?
我做错了什么?为什么会崩溃?
The App does not run on the main thread. I always open a new thread, which runs my program. The Main-Thread only handels the Screen Updates from SpriteKit, which I use for my programs.
该应用程序不在主线程上运行。我总是打开一个新线程来运行我的程序。主线程只处理来自 SpriteKit 的屏幕更新,我用于我的程序。
I just built up a new Cocoa-Based App and let the function run in the main-Thread and there it works. When I start a Thread in the Cocoa-App it crashes like in the SpriteKit Environment.
我刚刚构建了一个新的基于 Cocoa 的应用程序,并让该函数在主线程中运行并在那里运行。当我在 Cocoa-App 中启动一个线程时,它会像在 SpriteKit 环境中一样崩溃。
I need to start a new thread in the Sprite-Kit Environment because the updates will not be done if I start my main program directly from the AppDelegate. The main Program runs until the whole SpriteKit quits, so I have no chance, to do my work in the main thread.
我需要在 Sprite-Kit 环境中启动一个新线程,因为如果我直接从 AppDelegate 启动我的主程序,更新将不会完成。主程序运行直到整个 SpriteKit 退出,所以我没有机会在主线程中完成我的工作。
The crash occurs in the line with the runModal() and then in "NSSavePanel._spAuxiliaryStorage":
崩溃发生在 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 CocoaTest(54483,0x106f78000) malloc: *** error for object 0x60800017efc0: Heap corruption detected, free list canary is damaged
x2, %al
0x7fff84dfec52: andb dispatch_async(dispatch_get_main_queue())
{
// This commands are executed ansychronously
}
x1, %al
0x7fff84dfec54: xorb 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)
}
x1, %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
In the Terminal Window is shown:
在终端窗口中显示:
##代码##Any idea how to solve this problem without doing it inside the main thread?
知道如何解决这个问题而不在主线程中进行吗?
回答by j.s.com
The restrictions of the User Interface (UI) Calls, which are not Thread-Save, can be solved, when you use the following code, which executes a block of commands in the main thread asynchronously:
当您使用以下代码在主线程中异步执行命令块时,可以解决用户界面 (UI) 调用的限制(不是线程保存):
##代码##So you have to write your own functions for every built-in-function, which is not thread-save like this (example with the open file dialog):
所以你必须为每个内置函数编写你自己的函数,这不是像这样的线程保存(打开文件对话框的例子):
##代码##Please note, that the block is called asynchronously, that means you have to check, if the block has been processed and is finished or not. So I add a boolean variable "finsihed" which shows, when the block reaches its end. Without this you do not get the pathname but only an empty string.
请注意,该块是异步调用的,这意味着您必须检查该块是否已被处理并完成。因此,我添加了一个布尔变量“finsihed”,它显示块何时到达终点。没有这个,你不会得到路径名,而只会得到一个空字符串。
If you are interested, I will post my savefiledialog-function, too. Please leave a comment if so.
如果您有兴趣,我也会发布我的 savefiledialog 功能。如果是这样,请发表评论。
回答by j.s.com
Most of the User Interface (UI) Calls are not Thread-Save, that means that they only work without crash and unusual behaviour in the main-thread.
大多数用户界面 (UI) 调用都不是线程保存的,这意味着它们只能在主线程中没有崩溃和异常行为的情况下工作。
This is the problem with NSOpenPanel Calls, too. When calling from the main-thread everything is OK.
这也是 NSOpenPanel 调用的问题。从主线程调用时一切正常。