Swift 命令行程序中的 CFRunLoop
Posted
技术标签:
【中文标题】Swift 命令行程序中的 CFRunLoop【英文标题】:CFRunLoop in Swift Command Line Program 【发布时间】:2014-08-04 19:54:43 【问题描述】:我正在使用第三方框架(如果我正确理解代码)在 Swift 中编写命令行应用程序,该框架依赖 GCD 回调来在套接字接收数据时完成某些操作。为了更好地理解框架,我一直在玩一个示例 Cocoa 应用程序,框架的作者编写了一个与框架一起使用的示例。
因为示例应用程序是一个 Cocoa 应用程序,所以运行循环是自动处理的。我将示例应用程序(MIT 许可证)中的代码 sn-ps 包含在内,以了解其工作原理:
class AppDelegate: NSObject, NSApplicationDelegate
var httpd : Connect!
func startServer()
httpd = Connect()
.onLog
[weak self] in // unowned makes this crash
self!.log($0)
.useQueue(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0))
...
httpd.listen(1337)
...
func applicationDidFinishLaunching(aNotification: NSNotification?)
startServer()
...
我想修改示例应用程序以从命令行运行。当我将 startServer() 函数放入命令行应用程序时,它会运行,但套接字在打开后立即关闭,并且程序以退出代码 0 完成执行。这是预期的行为,因为没有运行循环在 Xcode 命令行项目中,因此程序不知道等待套接字接收数据。
我相信让套接字保持打开状态并使程序持续运行的正确方法是将主线程放在 CFRunLoop 中。我查看了 Apple 的文档,除了基本的 API 参考之外,Swift 中没有任何关于线程的内容。我查看了第三方资源,但它们都涉及 ios 和 Cocoa 应用程序中的备用线程。如何正确实现主线程的 CFRunLoop?
【问题讨论】:
【参考方案1】:看起来 Martin R 的答案应该有效,但是我能够通过一个函数调用让套接字保持打开状态。在 startServer() 函数的最后,我放了一行:
CFRunLoopRun()
哪个有效。
【讨论】:
调用这个函数后如何结束run loop? 我想通了:CFRunLoopStop(CFRunLoopGetMain())
【参考方案2】:
NSRunLoop Class Reference 有一个简单的运行循环的例子:
BOOL shouldKeepRunning = YES; // global
NSRunLoop *theRL = [NSRunLoop currentRunLoop];
while (shouldKeepRunning && [theRL runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
可以翻译成 Swift:
var shouldKeepRunning = true // global
let theRL = NSRunLoop.currentRunLoop()
while shouldKeepRunning && theRL.runMode(NSDefaultRunLoopMode, beforeDate: NSDate.distantFuture())
或者,调用可能就足够了
dispatch_main()
Swift 3.1 更新:
let theRL = RunLoop.current
while shouldKeepRunning && theRL.run(mode: .defaultRunLoopMode, before: .distantFuture)
或
dispatchMain()
【讨论】:
事实上RunLoop.current()
现在是var
所以应该是RunLoop.current
以上是关于Swift 命令行程序中的 CFRunLoop的主要内容,如果未能解决你的问题,请参考以下文章
C 中的 FTDI D2XX API 在命令行控制台上工作,但在由 Xcode 和 Swift 编程在 macOS 上构建的应用程序中始终返回零
Swift 命令行工具未接收 DistributedNotificationCenter 通知