Using NSURLSession from a Swift command line program

Fred Clausen picture Fred Clausen · Jun 8, 2015 · Viewed 7.8k times · Source

I'm trying to test a little proof-of-concept command line app prior to integrating it into a larger app. What I'm trying to do is download some data using NSURLSession using this example. However it appears that if I use the examples given in a simple OS X command line app then the app exits prior to the data being retrieved.

How can I download data from a stand-alone command line app using NSURLSession? What I've read about is using NSRunLoop however I've not yet found a clear example in Swift so if NSRunLoop is actually the way to go then any examples would be appreciated.

Any other strategies for downloading data from a URL for a Swift command line app is also welcome (infinite while loop?).

Answer

nielsbot picture nielsbot · Jun 8, 2015

You can use a semaphore to block the current thread and wait for your URL session to finish.

Create the semaphore, kick off your URL session, then wait on the semaphore. From your URL session completion callback, signal the semaphore.

You could use a global flag (declare a volatile boolean variable) and poll that from a while loop, but that is less optimal. For one thing, you're burning CPU cycles unnecessarily.

Here's a quick example I did using a 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()