web-dev-qa-db-ja.com

Swift=

SwiftでNSURLSessionを介して何らかの方法で同期HTTPリクエストを実行できますか?

次のコードを使用して非同期リクエストを実行できます。

if let url = NSURL(string: "https://2ch.hk/b/threads.json") {
            let task = NSURLSession.sharedSession().dataTaskWithURL(url) {
                (data, response, error) in

                var jsonError: NSError?
                let jsonDict = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: &jsonError) as [String: AnyObject]
                if jsonError != nil {
                    return
                }

                // ...
            }
            task.resume()
        }

しかし、同期リクエストはどうでしょうか?

前もって感謝します。

58
FrozenHeart

このNSURLSession拡張機能を使用して、同期メソッドを追加できます。

extension NSURLSession {
    func synchronousDataTaskWithURL(url: NSURL) -> (NSData?, NSURLResponse?, NSError?) {
        var data: NSData?, response: NSURLResponse?, error: NSError?

        let semaphore = dispatch_semaphore_create(0)

        dataTaskWithURL(url) {
            data = $0; response = $1; error = $2
            dispatch_semaphore_signal(semaphore)
        }.resume()

        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)

        return (data, response, error)
    }
}

Swift 3:の更新

extension URLSession {
    func synchronousDataTask(with url: URL) -> (Data?, URLResponse?, Error?) {
        var data: Data?
        var response: URLResponse?
        var error: Error?

        let semaphore = DispatchSemaphore(value: 0)

        let dataTask = self.dataTask(with: url) {
            data = $0
            response = $1
            error = $2

            semaphore.signal()
        }
        dataTask.resume()

        _ = semaphore.wait(timeout: .distantFuture)

        return (data, response, error)
    }
}
65
Nick Keets

同じ問題について議論しているAppleスレッド

+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request  
    returningResponse:(__autoreleasing NSURLResponse **)responsePtr  
    error:(__autoreleasing NSError **)errorPtr {  
    dispatch_semaphore_t    sem;  
    __block NSData *        result;  

    result = nil;  

    sem = dispatch_semaphore_create(0);  

    [[[NSURLSession sharedSession] dataTaskWithRequest:request  
        completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {  
        if (errorPtr != NULL) {  
            *errorPtr = error;  
        }  
        if (responsePtr != NULL) {  
            *responsePtr = response;  
        }  
        if (error == nil) {  
            result = data;  
        }  
        dispatch_semaphore_signal(sem);  
    }] resume];  

    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);  

   return result;  
}  

クインによる回答「エスキモー!」 Apple開発者関係、開発者テクニカルサポート、コアOS /ハードウェア

36
Umar Farooque

代わりにURLRequestを使用するように回答の1つを更新したため、代わりにPUTなどを使用できます。

extension URLSession {
    func synchronousDataTask(urlrequest: URLRequest) -> (data: Data?, response: URLResponse?, error: Error?) {
        var data: Data?
        var response: URLResponse?
        var error: Error?

        let semaphore = DispatchSemaphore(value: 0)

        let dataTask = self.dataTask(with: urlrequest) {
            data = $0
            response = $1
            error = $2

            semaphore.signal()
        }
        dataTask.resume()

        _ = semaphore.wait(timeout: .distantFuture)

        return (data, response, error)
    }
}

私はこのように呼んでいます。

var request = URLRequest(url: url1)
request.httpBody = body
request.httpMethod = "PUT"
let (_, _, error) = URLSession.shared.synchronousDataTask(urlrequest: request)
if let error = error {
    print("Synchronous task ended with error: \(error)")
}
else {
    print("Synchronous task ended without errors.")
}
14
Jonny