Как предотвратить выход из командной строки инструмента до завершения асинхронной операции
В инструменте командной строки swift 2 (main.swift) у меня есть следующее:
import Foundation
print("yay")
var request = HTTPTask()
request.GET("http://www.stackoverflow.com", parameters: nil, completionHandler: {(response: HTTPResponse) in
if let err = response.error {
print("error: \(err.localizedDescription)")
return //also notify app of failure as needed
}
if let data = response.responseObject as? NSData {
let str = NSString(data: data, encoding: NSUTF8StringEncoding)
print("response: \(str)") //prints the HTML of the page
}
})
Консоль показывает "yay", а затем выходит (программа завершена кодом выхода: 0), казалось бы, не дожидаясь завершения запроса. Как я мог предотвратить это?
В коде используется swiftHTTP
Я думаю, мне может понадобиться NSRunLoop, но нет быстрого примера
Ответы
Ответ 1
Я понимаю, что это старый вопрос, но вот решение, на котором я остановился. Использование DispatchGroup.
let dispatchGroup = DispatchGroup()
for someItem in items {
dispatchGroup.enter()
doSomeAsyncWork(item: someItem) {
dispatchGroup.leave()
}
}
dispatchGroup.notify(queue: DispatchQueue.main) {
exit(EXIT_SUCCESS)
}
dispatchMain()
Ответ 2
Добавление RunLoop.main.run()
в конец файла является одним из вариантов. Подробнее о другом подходе с использованием семафора здесь
Ответ 3
Вы можете вызвать dispatchMain()
в конце main. Это запускает диспетчер главной очереди GCD и никогда не возвращается, поэтому он предотвратит выход основного потока. Тогда вам просто нужно явно вызвать exit()
для выхода из приложения, когда вы будете готовы (иначе приложение командной строки зависает).
import Foundation
let url = URL(string:"http://www.stackoverflow.com")!
let dataTask = URLSession.shared.dataTask(with:url) { (data, response, error) in
// handle the network response
print("data=\(data)")
print("response=\(response)")
print("error=\(error)")
// explicitly exit the program after response is handled
exit(EXIT_SUCCESS)
}
dataTask.resume()
// Run GCD main dispatcher, this function never returns, call exit() elsewhere to quit the program or it will hang
dispatchMain()
Ответ 4
Не зависеть от времени. Вы должны попробовать это
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
Ответ 5
Если вам нужна не что-то, что требует кода "уровня производства", но некоторый быстрый эксперимент или попытка фрагмента кода, вы можете сделать это следующим образом:
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
Дополнительная информация: fooobar.com/questions/383894/...
Обратите внимание на, что вы не должны полагаться на фиксированное время выполнения в вашей архитектуре.
Ответ 6
Swift 4: RunLoop.main.run()
В конце вашего файла