web-dev-qa-db-ja.com

非同期操作が完了する前にコマンドラインツールが終了しないようにする方法

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 が必要かもしれませんが、Swiftの例はありません

29
codecowboy

これは古い質問だと思いますが、ここで私が終わらせた解決策を示します。 DispatchGroup を使用します。

let dispatchGroup = DispatchGroup()

for someItem in items {
    dispatchGroup.enter()
    doSomeAsyncWork(item: someItem) {
        dispatchGroup.leave()
    }
}

dispatchGroup.notify(queue: DispatchQueue.main) {
    exit(EXIT_SUCCESS)
}
dispatchMain()
13
skwashua

ファイルの最後にRunLoop.main.run()を追加するのも1つのオプションです。セマフォを使用した別のアプローチの詳細 here

25
codecowboy

Mainの最後でdispatchMain()を呼び出すことができます。これにより、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()
10
Mike Vosseller

タイミングに依存しないでください。

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
7
thiagoh

あなたの必要性がではない何か「生産レベル」のコードを必要とするが、いくつかの迅速な実験または一部のトライアウトコード、あなたはこのようにそれを行うことができます:

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

詳細: https://stackoverflow.com/a/40870157/469614


注意してくださいアーキテクチャで固定実行時間に依存するべきではありません。

3
Vexy

スウィフト4:RunLoop.main.run()

ファイルの最後に

2
Chris Karani