9

我正在使用第三方框架在 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?

4

2 回答 2

7

NSRunLoop类参考 有一个简单运行循环的示例:

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()
于 2014-08-04T20:20:48.530 回答
7

看起来 Martin R 的答案应该有效,但是我能够通过一个函数调用让套接字保持打开状态。在 startServer() 函数的末尾,我放了一行:

CFRunLoopRun()

哪个有效。

于 2014-08-04T20:25:43.393 回答