このコードは here にあり、Swift 2。
_ func send(url: String, f: (String)-> ()) {
var request = NSURLRequest(URL: NSURL(string: url)!)
var response: NSURLResponse?
var error: NSErrorPointer = nil
var data = NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: error)
var reply = NSString(data: data, encoding: NSUTF8StringEncoding)
f(reply)
}
_
しかし、関数NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: error)
は非推奨であり、Swiftで同期リクエストを実行する方法がわかりません。代替は非同期です。どうやらAppleは、それを同期的に実行できる唯一の関数を非推奨にしました。
どうやってやるの?
廃止の背後には理由があります-それはまったく使用できません。疫病としての同期ネットワーク要求を避ける必要があります。これには2つの主な問題と1つの利点しかありません(使いやすいですが、非同期ではありませんか?):
これの代わりに、非同期リクエストを使用してください:
NSURLConnection.sendAsynchronousRequest(request, queue: queue, completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
// Handle incoming data like you would in synchronous request
var reply = NSString(data: data, encoding: NSUTF8StringEncoding)
f(reply)
})
iOS9非推奨
IOS9では、このメソッドは廃止されているため、代わりにNSURLSessionを使用することをお勧めします。
let session = NSURLSession.sharedSession()
session.dataTaskWithRequest(request) { (data, response, error) -> Void in
// Handle incoming data like you would in synchronous request
var reply = NSString(data: data, encoding: NSUTF8StringEncoding)
f(reply)
}
really同期的に実行したい場合は、常にセマフォを使用できます。
func send(url: String, f: (String) -> Void) {
var request = NSURLRequest(URL: NSURL(string: url)!)
var error: NSErrorPointer = nil
var data: NSData
var semaphore = dispatch_semaphore_create(0)
try! NSURLSession.sharedSession().dataTaskWithRequest(request) { (responseData, _, _) -> Void in
data = responseData! //treat optionals properly
dispatch_semaphore_signal(semaphore)
}.resume()
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
var reply = NSString(data: data, encoding: NSUTF8StringEncoding)
f(reply)
}
編集:ハックを追加!したがって、コードは機能しますが、実稼働コードではこれを行わないでください
func send(url: String, f: (String) -> Void) {
guard let url = URL(string: url) else {
print("Error! Invalid URL!") //Do something else
return
}
let request = URLRequest(url: url)
let semaphore = DispatchSemaphore(value: 0)
var data: Data? = nil
URLSession.shared.dataTask(with: request) { (responseData, _, _) -> Void in
data = responseData
semaphore.signal()
}.resume()
semaphore.wait(timeout: .distantFuture)
let reply = data.flatMap { String(data: $0, encoding: .utf8) } ?? ""
f(reply)
}
@ fpg1503の回答に基づいて、Swift 3:
extension URLSession {
func synchronousDataTask(with request: URLRequest) throws -> (data: Data?, response: HTTPURLResponse?) {
let semaphore = DispatchSemaphore(value: 0)
var responseData: Data?
var theResponse: URLResponse?
var theError: Error?
dataTask(with: request) { (data, response, error) -> Void in
responseData = data
theResponse = response
theError = error
semaphore.signal()
}.resume()
_ = semaphore.wait(timeout: .distantFuture)
if let error = theError {
throw error
}
return (data: responseData, response: theResponse as! HTTPURLResponse?)
}
}
次に、単に呼び出します:
let (data, response) = try URLSession.shared.synchronousDataTask(with: request)
バックグラウンドスレッドでは、同期要求が適切な場合があります。非同期リクエストなどでいっぱいのコードベースを変更するのが複雑で不可能な場合があります。その後、現在のシステムに非同期としてフォールドできない小さなリクエストがあります。同期が失敗した場合、データは取得されません。シンプル。ファイルシステムの動作を模倣します。
確かにあらゆる種類の不測の事態をカバーしているわけではありませんが、非同期でカバーされていない不測の事態もたくさんあります。