8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

如何防止命令行工具在异步操作完成之前退出

Senocico Stelian 1月前

60 0

在 swift 2 命令行工具(main.swift)中,我有以下内容:import Foundationprint(\'yay\')var request = HTTPTask()request.GET(\'http://www..com\',参数:nil,completionH...

在 swift 2 命令行工具(main.swift)中,我有以下内容:

import Foundation
print("yay")

var request = HTTPTask()
request.GET("http://www..com", parameters: nil, completionHandler: {(response: HTTPResponse) in
    if let err = response.error {
        print("error: \(err.localizedDescription)")
        return //also notify app of failure as needed
    }
    if let data = response.responseObject as? NSData {
        let str = NSString(data: data, encoding: NSUTF8StringEncoding)
        print("response: \(str)") //prints the HTML of the page
    }
})

控制台显示“yay”,然后退出(程序以退出代码:0 结束),似乎从未等待请求完成。我该如何防止这种情况发生?

代码使用 swiftHTTP

我想我可能需要一个 NSRunLoop ,但没有快速示例

帖子版权声明 1、本帖标题:如何防止命令行工具在异步操作完成之前退出
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由Senocico Stelian在本站《objective-c》版块原创发布, 转载请注明出处!
最新回复 (0)
  • @trojanfoe 不一定,但我对这两种情况都感兴趣,异步与否。我决定尝试使用

  • 如果您只是在调试,则可以使用 readline(),它将保持运行循环运行以等待输入。或者您可以使用它来实际让用户退出他们的选择,检查输入是否与 \'y\' 或其他内容相符

  • 我意识到这是一个老问题,但这是我最终找到的解决方案。使用 DispatchGroup .

    let dispatchGroup = DispatchGroup()
    
    for someItem in items {
        dispatchGroup.enter()
        doSomeAsyncWork(item: someItem) {
            dispatchGroup.leave()
        }
    }
    
    dispatchGroup.notify(queue: DispatchQueue.main) {
        exit(EXIT_SUCCESS)
    }
    dispatchMain()
    
  • 添加 RunLoop.main.run() 到文件末尾是一种选择。有关使用信号量的另一种方法的更多信息,请参见 此处

  • Swift 5:RunLoop.current.run(mode: .default, before: .distantFuture) 或简单的死循环 while true { }

  • 您可以 dispatchMain() 在 main 的末尾调用。这将运行 GCD 主队列调度程序并且永不返回,因此它将阻止主线程退出。然后,您只需要 exit() 在准备就绪时明确调用以退出应用程序(否则命令行应用程序将挂起)。

    import Foundation
    
    let url = URL(string:"http://www..com")!
    let dataTask = URLSession.shared.dataTask(with:url) { (data, response, error) in
        // handle the network response
        print("data=\(data)")
        print("response=\(response)")
        print("error=\(error)")
    
        // explicitly exit the program after response is handled
        exit(EXIT_SUCCESS)
    }
    dataTask.resume()
    
    // Run GCD main dispatcher, this function never returns, call exit() elsewhere to quit the program or it will hang
    dispatchMain()
    
  • Aca 1月前 0 只看Ta
    引用 8

    也许是因为反对者找不到 dispatchMain(),所以它被否决了。我认为 Mike 指的是 dispatch_main()。

  • dispatch_main() 用于 obj-c。在 Swift 中它是 dispatchMain() developer.apple.com/documentation/dispatch/1452860-dispatchmain

  • Xcode 10.1 在使用此功能时似乎存在错误,除非您退出 Xcode,否则不会让您停止该过程(kill -9 会停止它,但 Xcode 无法弄清楚这一点)。但是 RunLoop.main.run() 可以工作

  • @gprasant 请解释为什么 displatchMain() 比 DispatchSemaphore( value: 0) 更好

  • Zacc 1月前 0 只看Ta
    引用 12

    不要依赖时间。你应该试试这个

    let sema = DispatchSemaphore(value: 0)
    
    let url = URL(string: "https://upload.wikimedia.org/wikipedia/commons/4/4d/Cat_November_2010-1a.jpg")!
    
    let task = URLSession.shared.dataTask(with: url) { data, response, error in
      print("after image is downloaded")
    
      // signals the process to continue
      sema.signal()
    }
    
    task.resume()
    
    // sets the process to wait
    sema.wait()
    
  • Swift 4: RunLoop.main.run()

    在文件末尾

  • 如果您的需求 不是 需要“生产级”代码,而是一些 快速实验或一段代码的试用 ,您可以这样做:

    Swift 3 系统

    //put at the end of your main file
    RunLoop.main.run(until: Date(timeIntervalSinceNow: 15))  //will run your app for 15 seconds only
    

    更多信息: https://.com/a/40870157/469614


    请注意 ,您不应该依赖架构中的固定执行时间。

  • 为异步任务硬编码时间间隔从来都不是一个好主意。命令行界面应该运行循环(不设置超时),并在从完成块返回后明确停止它。任何超时都应该由 HTTPTask 或 URLSession 类控制。

  • 引用 16

    sleep(15) 能起到同样的效果吗?我在 CodeRunner 中就是这样做的

  • 只需补充一点:为了使其无限期地运行,您可以使用 Date.distantFuture。

  • 如今,我们将使用 Swift 并发 并简化 await the async 。例如,

    do {
        guard let url = URL(string: "https://.com") else {
            throw URLError(.badURL)
        }
    
        let (data, _) = try await URLSession.shared.data(from: url)
        if let string = String(data: data, encoding: .utf8) {
            print(string)
        } else {
            print("Unable to generate string representation")
        }
    } catch {
        print(error)
    }
    

    与传统的完成处理程序模式不同,如果您 await 一项 async 任务,则命令行应用程序将不会在异步任务完成之前终止。

    有关更多信息,请参阅 WWDC 2021 视频 Meet async/await 或该页面上列出的任何“相关视频”。

  • // Step 1: Add isDone global flag
    
    var isDone = false
    
    // Step 2: Set isDone to true in callback
    
    request.GET(...) {
        ...
        isDone = true
    }
    
    
    // Step 3: Add waiting block at the end of code
    
    while(!isDone) {
        // run your code for 0.1 second
        RunLoop.main.run(until: Date(timeIntervalSinceNow: 0.1))
    }
    
  • 除了 Rob 的 答案之外(Swift 5.5+),还有一种方便的方法来创建异步命令行界面

    @main
    struct AsyncCLI { // the name is arbitrary 
        static func main() async throws {
            // your code goes here
        }
    }
    

    重要的:

    • 封闭文件不得命名 main.swift
返回
作者最近主题: