从 Swift 命令行程序使用 NSURLSession

Using NSURLSession from a Swift command line program

我正在尝试先测试一些概念验证命令行应用程序,然后再将其集成到更大的应用程序中。我想做的是使用 this example 使用 NSURLSession 下载一些数据。但是,如果我使用简单的 OS X 命令行应用程序中给出的示例,那么应用程序会在检索数据之前退出。

如何使用 NSURLSession 从独立的命令行应用下载数据?我读到的是使用 NSRunLoop 但是我还没有在 Swift 中找到一个明确的例子所以如果 NSRunLoop 实际上是要走的路那么任何例子都将不胜感激。

也欢迎从 URL 为 Swift 命令行应用程序下载数据的任何其他策略(无限 while 循环?)。

您可以使用信号量来阻塞当前线程并等待 URL 会话完成。

创建信号量,启动您的 URL 会话,然后等待信号量。从您的 URL 会话完成回调中,发出信号量。

您可以使用一个全局标志(声明一个 volatile 布尔变量)并从 while 循环中轮询它,但这不是最佳选择。一方面,您不必要地消耗 CPU 个周期。

这是我使用 playground 做的一个简单示例:

import Foundation

var sema = DispatchSemaphore( value: 0 )

class Delegate : NSObject, URLSessionDataDelegate
{
    func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data)
    {
        print("got data \(String(data: data, encoding: .utf8 ) ?? "<empty>")");
        sema.signal()
    }
}

let config = URLSessionConfiguration.default
let session = URLSession(configuration: config, delegate: Delegate(), delegateQueue: nil )

guard let url = URL( string:"http://apple.com" ) else { fatalError("Could not create URL object") }

session.dataTask( with: url ).resume()    

sema.wait()

为了概念证明或 tryouts/testing 目的,您可以通过 硬编码 一些超时时间来简化异步复杂性,直到您的东西完成。 (见下面的注释)

SWIFT 5

    //...your magic here
    // add a little iness to make it fun at least...
    RunLoop.main.run(until: Date() + 0x10)  //oh boi, default init && hex craze 
    // yeah, 16 seconds timeout

    // or even worse (!)
    RunLoop.main.run(until: .distantFuture)

SWIFT 3 或更早

    //...your stuff here
    RunLoop.main.run(until: Date(timeIntervalSinceNow: 15))  //will execute things on main loop for 15 seconds

注释 :

  1. 不要在生产中使用它
  2. 遵守第一条规则

这是一种非常快速而肮脏的 方法来克服并行性的严重问题。探索此问题的其他答案中描述的更好、更复杂的解决方案。

试试这个

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");
  sema.signal(); // signals the process to continue
};

task.resume();
sema.wait(); // sets the process to wait