title: Using completion handler together with DispatchQueue
body: <p>I have learned that concurrent <code>DispatchQueue</code> allows the code inside it to return immediately, hence not blocking the calling thread. This is usually used with background tasks loading large data.</p>
  
  <p>I have also learned that completion handler (for example, in <code>URLSession</code> ) allows the code inside handler to be executed after some task finishes. </p>
  
  <p>My question is: does it mean that concurrent dispatch queue and completion handler have overlapping purpose? If I already used completion handler, there is no need to wrap it with a concurrent dispatch queue?</p>
  
  <p>For example, below is a time-consuming data loading task using URLSession, is it a good idea to wrap it with a concurrent dispatch queue?</p>
  
  <pre><code>URLSession(configuration: URLSessionConfiguration.default).dataTask(with: propertiesRequest) { data, response, error in
          // print("within dataTask: data: \(data), response: \(response), error: \(error)")
          if let error = error {
              print(error)
          } else if let httpResponse = response as? HTTPURLResponse {
              if httpResponse.statusCode == 200 {
                  print("success: property task request")
  
  
                  do {
  
                      handler(responseDict, nil) // This is a function supplied by caller
  
                  } catch let error as NSError {
                      handler(nil, error)
                  }
              }
          }
      }
  </code></pre>