CFRunLoop в программе командной строки Swift

Я пишу приложение командной строки в Swift, используя стороннюю платформу, которая (если я правильно понимаю код) использует обратные вызовы GCD для выполнения определенных действий, когда сокет получает данные. Чтобы лучше понять фреймворк, я поэкспериментировал с примером приложения 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 для основного потока?

2 ответа

Кажется, что ответ Мартина Р. должен сработать, однако я смог заставить сокет оставаться открытым с помощью одного вызова функции. В конце функции startServer() я поставил строку:

CFRunLoopRun()

Который работал.

Ссылка класса 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()
Другие вопросы по тегам