highlights

2017年1月19日木曜日

[Swift3] URLSessionのdataTaskを同期させようとして応答が返ってこない時の対策

原因

共有されたdataTaskのスレッドからの呼び出しでDispatchSemaphoreを使っているため(URLSession.sharedなど)。参考にしたサイトは下記。この実装だとURLSession.sharedを使ってスレッドを共有したときに処理が返って来ない。

上手く動かない例
import Foundation

extension URLSession {
    func sync(with request:URLRequest) -> (data:Data?, response:URLResponse?, error:Error?) {
        let semaphore = DispatchSemaphore(value: 0)
        var _dat : Data?
        var _res : URLResponse?
        var _err : Error?
        self.dataTask(with: request) { dat, res, err in
            _dat = dat; _res = res; _err = err
            semaphore.signal()
            }.resume()
        _ = semaphore.wait(timeout: .distantFuture)
        return (_dat, _res, _err)
    }
}

let request = URLRequest(url:URL(string:"https://developer.apple.com/swift/")!)

URLSession.shared.dataTask(with: request) { data, response, error in
    let result = URLSession.shared.sync(with:request)
    let dataString = String(describing: NSString(data: result.data!, encoding: String.Encoding.utf8.rawValue))
    print(dataString)
}.resume()

解決策

別スレッドを使う。
URLSession.shared.dataTask(with: request) { data, response, error in
    let session = URLSession(configuration: .default)
    let result = session.sync(with:request)
    let dataString = String(describing: NSString(data: result.data!, encoding: String.Encoding.utf8.rawValue))
    print(dataString)
}.resume()

URLSesssion.sharedについての説明はこちら
The singleton shared session (which has no configuration object) is for basic requests. It is not as customizable as sessions that you create, but it serves as a good starting point if you have very limited requirements. You access this session by calling the shared() class method. See that method’s discussion for more information about its limitations.
考えてみれば当然ちゃ当然の動きだけど、てっきりdataTaskが非同期という認識があったため原因特定に時間がかかった。備忘録として書いておく。

0 件のコメント:

コメントを投稿