LoginSignup
7
3

More than 5 years have passed since last update.

URLSessionの拡張(URLSession#synchronousDataTask, URLSession#retryDataTask)

Posted at

URLSession拡張定義

extension URLSession {

    /*
     * synchronousDataTask
     * 
     * Httpデータを同期的に取得します。スレッドをブロックするので使用に注意してください。
     */

    func synchronousDataTask(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)
    }

    func synchronousDataTask(with url:URL) -> (data:Data?, response:URLResponse?, error:Error?) {
        return self.synchronousDataTask(with: URLRequest(url: url))
    }

    /*
     * retryDataTask
     * 
     * Httpデータ取得に失敗た場合に再度取得を試みます。取得に成功するまでtimesで指定した回数の再取得を試みます。
     */

    func retryDataTask(withRequest request:URLRequest, times num:Int=50, wait usec:useconds_t=200*1000, errorHandler:@escaping (Int, Error) -> ()={_,_ in}, completionHandler:@escaping (Data?, URLResponse?, Error?) -> ()) -> URLSessionDataTask {
        return self.dataTask(with: request) { dat, res, err in
            if let err = err, num > 0 {
                errorHandler(num, err)
                usleep(usec)
                self.retryDataTask(withRequest: request, times: num-1, wait: usec, errorHandler: errorHandler, completionHandler: completionHandler).resume()
            } else {
                completionHandler(dat, res, err)
            }
        }
    }

    func retryDataTask(withURL url:URL, times num:Int=50, wait usec:useconds_t=200*1000, errorHandler:@escaping (Int, Error) -> ()={_,_ in}, completionHandler:@escaping (Data?, URLResponse?, Error?) -> ()) -> URLSessionDataTask {
        return self.retryDataTask(withRequest: URLRequest(url: url), times: num, wait: usec, errorHandler: errorHandler, completionHandler: completionHandler)
    }
}

使用例

URLSession#synchronousDataTask

let url = URL(string: "http://localhost:8080/")!

let result = URLSession.shared.synchronousDataTask(with: url)

print( result.data, result.response, result.error )
print("complete.")

URLSession#retryDataTask

let url = URL(string: "http://localhost:8080/")!

// 単純データ取得

func get() {
    URLSession.shared.retryDataTask(withURL: url) { dat, _, _ in
        if let dat = dat, let body = String(data: dat, encoding: .utf8) {
            print(body)
        }
    }.resume()
}

// リトライを最大30回繰り返し。取得失敗の度にエラー情報を出力する。

let numberOfTimes = 30

func displayIndicator(count:Int, error:Error) {
    print("times:\(count)/\(numberOfTimes)")
    print(error)
}

func status() {
    URLSession.shared.retryDataTask(withURL: url, times: numberOfTimes, errorHandler: displayIndicator) { dat, res, err in
        if dat == nil, res == nil, let error = err {
            print(error)
        } else if let dat = dat, let response = res, err == nil, let body = String(data:dat, encoding:.utf8) {
            print(response)
            print(body)
        }
    }.resume()
}
7
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
3