我正在使用第三方框架在Swift中编写命令行应用程序(如果我理解正确的代码)依赖于GCD回调来在套接字接收数据时完成某些操作。为了更好地理解框架,我一直在使用框架作者编写的示例Cocoa应用程序来与框架一起使用。
因为示例应用程序是Cocoa应用程序,所以自动处理运行循环。我在示例应用程序(MIT许可证)中包含代码片段,以了解其工作原理:
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?
答案 0 :(得分:6)
似乎Martin R的答案应该有效,但是我能够通过单个函数调用使套接字保持打开状态。在startServer()函数结束时,我将行:
CFRunLoopRun()
哪个有效。
答案 1 :(得分:5)
NSRunLoop Class Reference 有一个简单的runloop示例:
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()