猿问

继续 OS X - 两个库调用系统函数

我发现至少为 Mac 编写一些具有或多或少常见 UI 的东西是很困难的。我的应用程序必须有托盘图标并且能够显示系统通知


问题是 goroutine 本身。在 Mac 上对 UI 框架的任何调用都要求从主线程调用,或者至少以线程安全的方式调用。


当我已经在运行 UI(嗯,对于 GUI 应用程序是必须的,不是吗?)并尝试显示通知时,就会出现问题。这样做的原因似乎是系统托盘包 Init 函数必须被锁定到主线程使用runtime.LockOsThread并且永远不会释放它。然后,如果我尝试显示也需要runtime.LockOsThread它的通知,则会导致以下错误:


2016-01-11 22:56:27.973 main[30162:4094392] *** Assertion failure in +[NSUndoManager _endTopLevelGroupings], /Library/Caches/com.apple.xbs/Sources/Foundation/Foundation-1256.1/Misc.subproj/NSUndoManager.m:359

2016-01-11 22:56:27.974 main[30162:4094392] +[NSUndoManager(NSInternal) _endTopLevelGroupings] is only safe to invoke on the main thread.

2016-01-11 22:56:27.977 main[30162:4094392] (

    0   CoreFoundation                      0x00007fff8d42bae2 __exceptionPreprocess + 178

    1   libobjc.A.dylib                     0x00007fff8bb03f7e objc_exception_throw + 48

    2   CoreFoundation                      0x00007fff8d42b8ba +[NSException raise:format:arguments:] + 106

    3   Foundation                          0x00007fff8cb4c88c -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 198

    4   Foundation                          0x00007fff8cad24c1 +[NSUndoManager(NSPrivate) _endTopLevelGroupings] + 170

    5   AppKit                              0x00007fff8514206a -[NSApplication run] + 844

    6   main                                0x0000000004166200 nativeLoop + 128

    7   main                                0x0000000004165bca _cgo_8c6479959095_Cfunc_nativeLoop + 26

    8   main                                0x000000000405a590 runtime.asmcgocall + 112

)

有解决方法吗?到目前为止我能想到的就是将 UI 和通知放入单独的二进制文件中,并使它们通过某种 IPC 与 main 进行通信。但我可能会遗漏一些东西。


一只名叫tom的猫
浏览 132回答 2
2回答

幕布斯6054654

由于这个问题没有足够的吸引力,我决定发布我在尝试解决此问题时发现的自己的解决方案。这不会被标记为答案,因为其他人可能会提供更好的解决方案。我提出UI过程中的一个(即部分使用系统托盘)到另一个二进制和使用调用它cmd := exec.Command(...)和cmd.Start()后来我管stdin,并stdout与那些通过这个子进程进行通信。示例代码可以在Github上找到。警告在这个要点中有一个错误,在子进程退出后,主进程将开始消耗 CPU 周期。随意自己修复它。我不想通过 RPC 的原因是因为这对于我想要实现的目标来说会变得有点过于复杂,并且没有提供简单的方法来进行双向通信。

慕田峪7331174

看起来您使用的两个库都正确用于runtime.LockOSThread进行仅主线程 API 调用;不幸的是,要使用多个这样的库,您必须做一些比提供的示例代码更有趣的事情。您需要编写自己的主线程/main.Main调用消息循环来处理对多个 MTO API 的调用。runtime.LockOSThread是使用此类 API 进行操作的解决方案的一部分;golang wiki有一个关于如何使用它与“仅从主线程调用”API 交互的页面。关于你的程序应该如何改变的极短的描述:您需要使用runtime.LockOSThreadinmain.init来确保主线程正在运行main.Main;main.Main应该重构为两部分:启动一个 goroutine 或 goroutines 运行之前的内容main.Main;进入消息循环接收消息以在一个或多个通道上执行某些主线程操作
随时随地看视频慕课网APP

相关分类

Go
我要回答