从Swift命令行程序中使用NSURLSession

时间:2015-06-08 06:21:03

标签: macos swift nsurlsession nsrunloop

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

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

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

4 个答案:

答案 0 :(得分:31)

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

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

您可以使用全局标志(声明一个易失性布尔变量)并从while循环中轮询,但这不是最佳。首先,你不必要地燃烧CPU周期。

这是我使用游乐场做的一个简单示例:

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()

答案 1 :(得分:5)

试试这个

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

答案 2 :(得分:3)

如果它仅用于测试目的,如果您的命令行应用程序的硬代码“执行时间”如下所示,则可以避免使用信号量:

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

这是非常快速和脏的方式来“启用”命令行应用程序等待其他线程完成。此外,您的应用程序将在超时到期后正常退出,而无需显式终止或取消应用程序进程。

注意

  1. 如果您的网络任务需要更多时间来完成,您可以更改“超时”期限。
  2. 如果你想要更严肃的等待机制(也就是不要在生产中使用它),这个“解决方案”肯定是不好的决定。

答案 3 :(得分:-1)

我用一个while循环和bool标志来解决这个问题,当url会话返回

时设置为true

Xcode&gt; MacOS&gt;控制台应用

main.swift

@ViewChild('focuserror') errorElement: ElementRef;
      ngAfterViewInit() {
        this.renderer.invokeElementMethod(this.errorElement.nativeElement.querySelector('.ng-invalid'), 'focus');
       }