我使用Mac的SpriteKit (而不是iOS)来运行我的程序。
在"AppDelegate"-Class的“AppDelegate”方法的末尾,我将启动初始化所需的所有内容。有些方法不喜欢从后台线程调用,比如设置窗口标题、调整窗口大小和其他一些任务。所以所有这些事情都是在主线程中完成的。
然后是我的问题:我不能简单地在"applicationDidFinishLaunching“方法的末尾运行我的主程序,因为当我这样做时,"applicationDidFinishLaunching”方法在我的主程序退出之前不会退出。我的主程序没有退出,因为它在启动程序后直接在屏幕上显示了一些动画。
在这种情况下,"applicationDidFinishLaunching“方法不会退出,SpriteKit不会重新绘制窗口,所以我的动画运行,但我看到一个白色窗口。
退出我的程序后,"applicationDidFinishLaunching“方法也退出了,我看到了动画的最后一张图片。
因此,我意识到了一个解决办法:我现在在"applicationDidFinishLaunching“方法中进行初始化,然后启动一个后台线程来运行我的主程序。
"applicationDidFinishLaunching“在启动后台线程后退出,窗口将按预期更新。所有的一切运行良好的背景线程做动画。
而现在的问题,我无法解决:我需要隐藏菜单栏,不是直接启动程序,而是在一段时间后。
NSMenu.setMenuBarVisible(false)当从主线程调用时,这样做没有问题,但是如果我从后台线程隐藏菜单栏,那么我可以隐藏它一次,使它可见一次,第二次隐藏它,以及当AppDelegate类中的异常第二次停止我的程序时:
Thread 1: EXC_BAD_ACCESS (code=EXC_i386_GPFLT)我解决这个问题的想法是发布一个事件,这个事件是由主线程处理的。但是如果我发布一个键盘事件,事件处理也是在后台线程中完成的。
像由用户选择菜单,而不是以编程的方式选择的事件是从主线程中分配的,但是我没有找到一种方法将一个事件发送到主线程中,而不是包含sendEvent命令的线程中:
NSApplication.sharedApplication().sendEvent(event!) // Called from background-thread有谁想过发送一个由主线程处理的事件吗?
或
完全在主线程中运行我的程序,没有问题,窗口内容根本没有绘制。第二个解决方案将是我最喜欢的,因为还有更多的东西,它们会在后台线程中产生问题。
也许我可以从另一种方法开始我的主程序,在"applicationDidFinishLaunching“完成之后的一段时间。
关于上述主题的一些更深层次的信息,但仍然没有解决办法:
我发现,存在一个函数"performSelectorOnMainThread“,它可以从像这样的called调用:
NSApplication.performSelectorOnMainThread(Selector(myFunctionToCall()), withObject: nil, waitUntilDone: true)此调用编译,调用我的函数,但在后台线程中,而不是在主线程上,并转储一个错误:
2015-01-17 20:11:09.142 AudioDatabase[4449:2099588] +[NSApplication (null selector)]: unrecognized selector sent to class 0x7fff7b1d8be0但是死刑还在继续。除了像NSApplication、NSObject、NSThread这样的类函数之外,我无法调用任何其他类型的函数。但我从来没有达到过主回路。
另一个想法是使用NSInvocation,但当我查看文档时,只有Objective部分出现。
如果可能的话,它将有助于简单地调用我的函数,无论参数是否在主线程中运行,并且可以在其中做一些事情。
发布于 2015-01-18 10:39:59
在后台线程中运行我的程序时,我发现了一种在主线程异步执行必要命令的方法。要做到这一点,您必须打电话:
dispatch_async(dispatch_get_main_queue())
{
// This block runs in the main thread
}所以我的问题是,在不破坏我的程序的情况下显示和隐藏菜单栏。下面是从后台线程调用的已完成的函数:
func m_MenuBarShow ()
{
dispatch_async(dispatch_get_main_queue())
{
NSMenu.setMenuBarVisible(true) // Class func, must be called on the Class (NSMenu) and not on the Instance (NSApp.sharedApp.mainMenu)
}
}
func m_MenuBarHide ()
{
dispatch_async(dispatch_get_main_queue())
{
NSMenu.setMenuBarVisible(false) // Class func
}
}请注意,在使用这个块时有一个小的限制:这个块称为异步,这意味着您必须确保它已经完成,直到对结果做一些事情。在显示菜单栏的情况下,这没有问题。但是,如果您想要打开文件这样的操作,就必须处理这个问题。
我将解释这一点,作为我另一个问题的答案。请看一看:Open File Dialog crashes in Swift
https://stackoverflow.com/questions/27965079
复制相似问题