Использование 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