Search code examples
swiftasynchronousrequestresponsensurlsession

How to Find which response belongs to which request in Async api calling using URLSession


I'm using URLSession to get the response from the API's in my iPhone app. In my case, I'm hitting around 10 requests of a same api at a time using Asynchronous API calling and I'm getting the response for all the requests. Now from those responses how can I find which response belongs to which request? Any help appreciated.


Solution

  • You have many ways to achieve this.

    1 - Basically, if you call your client function with an identifier, you will be able to retrieve it in your completion block:

    func call(with identifier: String, at url: URL) {
        URLSession.shared.dataTask(url: url) { (_, _, _) in
            print(identifier)
        }.resume()
    }
    

    2 - You can also use the taskIdentifier of an URLSessionDataTask. But to do this, you will need to use the delegate of your custom URLSession:

    self.session = URLSession(configuration: URLSessionConfiguration.default,
                              delegate: self,
                              delegateQueue: nil)
    

    then you will not use a completion block but the delegate function instead:

    func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) {
        print(dataTask.taskIdentifier)
    }
    

    (of course you need to know which task identifier has been set for which URLSessionDataTask)

    3 - If you need to access your identifier from your completion block, you can write a function which will happened it in the list of the parameter of the default completion block:

    func dataTask(session: URLSession,
                  url: URL,
                  identifier: String,
                  completionBlock: @escaping (String, Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask {
        return session.dataTask(with: url) { (data, response, error) in
            completionBlock(identifier, data, response, error)
        }
    }
    

    4 - If you need to have a custom identifier in a URLSessionDataTask object, you can add it using extension and associated object:

    extension URLSessionDataTask {
        var identifier: String? {
            get {
                let identifier = objc_getAssociatedObject(self, &kIdentiferId)
                if let id = identifier as? String {
                    return id
                } else {
                    return nil
                }
            }
            set {
                objc_setAssociatedObject(self, &kIdentiferId, newValue, .OBJC_ASSOCIATION_RETAIN)
            }
        }
    }
    
    private var kIdentiferId: Int8 = 100
    

    Then you can use it like this:

    let task = session.dataTask(url: url)
    task.identifier = "hello"