より大きなアプリに統合する前に、小さな概念実証コマンドラインアプリをテストしようとしています。私がやろうとしているのは、 この例 を使用してNSURLSessionを使用していくつかのデータをダウンロードすることです。ただし、単純なOS Xコマンドラインアプリで示した例を使用すると、データが取得される前にアプリが終了するようです。
NSURLSessionを使用してスタンドアロンコマンドラインアプリからデータをダウンロードするにはどうすればよいですか?私が読んだのは NSRunLoop を使用していますが、Swift)で明確な例をまだ見つけていないので、NSRunLoopが実際に進む方法である場合、どの例でも感謝します。
SwiftコマンドラインアプリのURLからデータをダウンロードするための他の戦略も歓迎します(無限のwhileループ?)。
セマフォを使用して現在のスレッドをブロックし、URLセッションが終了するのを待つことができます。
セマフォを作成し、URLセッションを開始して、セマフォを待ちます。 URLセッション完了コールバックから、セマフォにシグナルを送信します。
グローバルフラグ(揮発性ブール変数を宣言する)を使用して、whileループからポーリングすることもできますが、それは最適ではありません。一つには、CPUサイクルを不必要に消費しているということです。
これは私が遊び場を使って行った簡単な例です:
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()
これを試して
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
テスト目的のみの場合、コマンドラインアプリのハードコード「実行時間」を次のようにすると、セマフォの使用を回避できます。
Swift
//put at the end of your main file
RunLoop.main.run(until: Date(timeIntervalSinceNow: 15)) //will run your app for 15 seconds only
これは非常に迅速で汚い他のスレッドが終了するのを待つためにコマンドラインアプリを「有効にする」方法です。また、アプリのプロセスを明示的に強制終了またはキャンセルしなくても、タイムアウトの期限が切れるとアプリは正常に終了します。
[〜#〜]注[〜#〜]: