Can I somehow do a synchronous HTTP request via NSURLSession in Swift

Can I somehow do a synchronous HTTP request via NSURLSession in Swift?

I can do an asynchronous request via the following code:

  • How can I create a registeration form connected with an xml webservice?
  • Send POST parameters with MultipartFormData using Alamofire, in iOS Swift
  • HTTP “POST” request in iOS
  • How to open iOS app from browser?
  • With Data (not NSData), in fact how actually do you make a utf8 version of a jpeg?
  • iOS Multithreading - NSURLSession and UI updates
  • 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()
            }
    

    But what about synchronous request?

    Thanks in advance.

    4 Solutions Collect From Internet About “Can I somehow do a synchronous HTTP request via NSURLSession in Swift”

    You can use this NSURLSession extension to add a synchronous method:

    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)
        }
    }
    

    Update for 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)
        }
    }
    

    Apple thread discussing the same issue.

    + (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;  
    }  
    

    Answer by Quinn “The Eskimo!” Apple Developer Relations, Developer
    Technical Support, Core OS/Hardware

    Updated one of the answers to use a URLRequest instead, so we can use PUT etc instead.

    extension URLSession {
        func synchronousDataTask(urlrequest: URLRequest) -> (Data?, URLResponse?, 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)
        }
    }
    

    I’m calling like this.

    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.")
    }
    

    Be careful with synchronous requests because it can result in bad user experience but I know sometimes its necessary.
    For synchronous requests use NSURLConnection:

    func synchronousRequest() -> NSDictionary {
    
            //creating the request
            let url: NSURL! = NSURL(string: "exampledomain/...")
            var request = NSMutableURLRequest(URL: url)
            request.HTTPMethod = "GET"
            request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    
    
            var error: NSError?
    
            var response: NSURLResponse?
    
            let urlData = NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: &error)
    
            error = nil
            let resultDictionary: NSDictionary = NSJSONSerialization.JSONObjectWithData(urlData!, options: NSJSONReadingOptions.MutableContainers, error: &error) as! NSDictionary
    
            return resultDictionary
        }