Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

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

More than 3 years have passed since last update.

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()
}
tom-u
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away