如何退出runloop?

时间:2017-05-06 20:50:40

标签: swift swift3

所以,我有一个Swift命令行程序:

import Foundation

print("start")

startAsyncNetworkingStuff()

RunLoop.current.run()

print("end")

代码编译没有错误。异步网络代码运行得很好,获取其所有数据,打印结果,并最终调用其完成功能。

如何让完成功能突破当前的runloop以便最后一个"结束"得到印刷?

添加了:

使用以下内容替换RunLoop.current.run():

print("start")

var shouldKeepRunning = true

startAsyncNetworkingStuff()

let runLoop = RunLoop.current
while (   shouldKeepRunning
       && runLoop.run(mode:   .defaultRunLoopMode,
                      before: .distantFuture ) ) {
}

print("end")

设置

shouldKeepRunning = false
异步网络完成功能中的

仍然不会导致"结束"打印。 (这是通过将带有print语句的shouldKeepRunning = false语句括起来进行检查的,这些语句实际上是打印到控制台)。缺少什么?

3 个答案:

答案 0 :(得分:9)

对于命令行界面,请使用此模式并向 AsyncNetworkingStuff 添加完成处理程序(感谢Rob提供代码改进):

print("start")

let runLoop = CFRunLoopGetCurrent()
startAsyncNetworkingStuff() { result in 
   CFRunLoopStop(runLoop)
}

CFRunLoopRun()
print("end")
exit(EXIT_SUCCESS)

请不要使用丑陋的while循环。

答案 1 :(得分:1)

(回答我自己的问题)

将以下代码段添加到我的异步网络完成代码中,可以打印“结束”:

DispatchQueue.main.async {
    shouldKeepRunning = false
}

答案 2 :(得分:1)

以下是使用Swift 4.2在macOS命令行工具中使用URLSession的方法

// Mac Command Line Tool with Async Wait and Exit
import Cocoa

// Store a reference to the current run loop
let runLoop = CFRunLoopGetCurrent()

// Create a background task to load a webpage
let url = URL(string: "http://SuperEasyApps.com")!
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
    if let data = data {
        print("Loaded: \(data) bytes")
    }
    // Stop the saved run loop
    CFRunLoopStop(runLoop)
}
task.resume()

// Start run loop after work has been started
print("start")
CFRunLoopRun()
print("end") // End will print after the run loop is stopped

// If your command line tool finished return success,
// otherwise return EXIT_FAILURE
exit(EXIT_SUCCESS)

您必须在开始之前使用对运行循环的引用来调用stop函数(如上所示),或者使用GCD才能按预期退出。

func stopRunLoop() {
    DispatchQueue.main.async {
        CFRunLoopStop(CFRunLoopGetCurrent())
    }
}

参考

https://developer.apple.com/documentation/corefoundation/1542011-cfrunlooprun

  

运行循环可以递归运行。您可以从任何运行循环调用中调用CFRunLoopRun(),并在当前线程的调用堆栈上创建嵌套的运行循环激活。

https://developer.apple.com/documentation/corefoundation/1541796-cfrunloopstop

  

如果运行循环嵌套有一个激活从另一个激活开始的标注,则仅退出最内部的激活。