Search code examples
iosswiftgrand-central-dispatchaccess-token

How to create queue and start it manually


In my application, I have to implement a refresh token logic. I would like that during the refresh token process all requests sent to be kept in a queue and as soon as my process is finished, I start the queue

For example, I want something like this:

let queue = DispatchQueue(label: "myQueue", attributes: .concurrent)  

queue.async {
    // request One
}

queue.async {
    // request Two
}

And when the refresh token process finished:

queue.send()

Solution

  • In my application I have to implement a refresh token logic. I would like that during the refresh token process all requests sent be kept in a queue and as soon as my process is finished I start the queue

    If you want to create a queue and delay the starting of its tasks, just suspend it, e.g.:

    let queue = DispatchQueue(label: "myQueue", attributes: .concurrent)  
    queue.suspend()
    
    queue.async {
        // request One
    }
    
    queue.async {
        // request Two
    }
    
    fetchToken { result in
        switch result {
        case .success(let token):
            // do something with token
            print(token)
            queue.resume()
    
        case .failure(let error):
            // handle the error
            print(error)
        }
    }
    

    That’s how you suspend and resume dispatch queues. Note, suspend only prevent items from starting on a queue, but has no affect on tasks that are already running. That is why I suspended the queue before dispatching items to it.

    But the above begs the question of what you want to do in that failure scenario. You just have a queue sitting there with a bunch of scheduled tasks. You could, theoretically, keep references to those dispatched blocks (by using DispatchWorkItem pattern rather than just simple closures, and you could cancel those items), but I’d probably reach for an operation queue, e.g.

    let queue = OperationQueue()
    queue.isSuspended = true
    
    queue.addOperation {
        // request One
    }
    
    queue.addOperation {
        // request Two
    }
    
    fetchToken { result in
        switch result {
        case .success(let token):
            // do something with token
            print(token)
            queue.isSuspended = false
    
        case .failure(let error):
            // handle the error
            print(error)
            queue.cancelAllOperations()
        }
    }
    

    This is the same as the above, but we can cancel all of those queued operations with cancelAllOperations.


    By the way, you can create custom Operation subclass that handles tasks that are, themselves, asynchronous. And I’m presuming your “request One” and “request Two” are asynchronous network requests. See looking for a specific example where Operation is preferred over GCD or vice-versa for a discussion of when one might prefer OperationQueue over DispatchQueue.