Использование NSURLSession из командной строки Swift

Я пытаюсь протестировать небольшое приложение командной строки с доказательством концепции, прежде чем интегрировать его в более крупное приложение. То, что я пытаюсь сделать, это загрузить некоторые данные, используя NSURLSession, используя этот пример. Однако представляется, что если я использую примеры, приведенные в простом приложении командной строки OS X, приложение прекращает работу до получения данных.

Как загрузить данные из автономного приложения командной строки с помощью NSURLSession? То, что я читал, использует NSRunLoop, однако я еще не нашел ясного примера в Swift, поэтому, если NSRunLoop на самом деле способ, то любые примеры будут быть оцененным.

Любые другие стратегии для загрузки данных из URL-адреса для приложения командной строки Swift также приветствуются (бесконечный цикл while?).

Ответы

Ответ 1

Вы можете использовать семафор, чтобы заблокировать текущий поток и дождаться завершения сеанса URL.

Создайте семафор, начните сеанс URL-адреса, а затем подождите семафора. От вашего обратного вызова завершения сеанса URL-адреса передайте семафор.

Вы можете использовать глобальный флаг (объявить volatile boolean variable) и опросить это из цикла while, но это менее оптимально. Во-первых, вы сжигаете циклы процессора без необходимости.

Вот быстрый пример, который я использовал с детской площадкой:

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

Ответ 2

Если это просто для тестирования, вы можете избежать использования семафора, если вы жестко запрограммируете "время выполнения" вашего приложения командной строки следующим образом:

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

Это очень быстрый и грязный способ "разрешить" приложениям командной строки ждать окончания других потоков. Кроме того, ваше приложение будет завершено нормально после истечения таймаута, без необходимости явно убивать или отменять процесс приложения.

ПРИМЕЧАНИЕ:

  • Вы можете изменить период ожидания, если для ваших сетевых задач требуется больше времени.
  • Это "решение", безусловно, плохое решение, если вы хотите более серьезный механизм ожидания (иначе НЕ ИСПОЛЬЗУЙТЕ ИСПОЛЬЗОВАТЬ ЭТО В ПРОИЗВОДСТВЕ)

Ответ 3

Попробуйте это

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