Thanks for being a part of WWDC25!

How did we do? We’d love to know your thoughts on this year’s conference. Take the survey here

urlSession(_:dataTask:didReceive:) not called when using completion handler-based dataTask(w

Description: I'm noticing that when using the completion handler variant of URLSession.dataTask(with:), the delegate method urlSession(_:dataTask:didReceive:) is not called—even though a delegate is set when creating the session.

Here's a minimal reproducible example:

✅ Case where delegate method is called:

class CustomSessionDelegate: NSObject, URLSessionDataDelegate {
    func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
        print("✅ Delegate method called: Data received")
    }
}

let delegate = CustomSessionDelegate()
let session = URLSession(configuration: .default, delegate: delegate, delegateQueue: nil)

let request = URLRequest(url: URL(string: "https://httpbin.org/get")!)
let task = session.dataTask(with: request) // ✅ No completion handler
task.resume()

In this case, the delegate method didReceive is called as expected.

❌ Case where delegate method is NOT called:

class CustomSessionDelegate: NSObject, URLSessionDataDelegate {
    func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
        print("❌ Delegate method NOT called")
    }
}

let delegate = CustomSessionDelegate()
let session = URLSession(configuration: .default, delegate: delegate, delegateQueue: nil)

let request = URLRequest(url: URL(string: "https://httpbin.org/get")!)
let task = session.dataTask(with: request) { data, response, error in
    print("Completion handler called")
}
task.resume()

Here, the completion handler is executed, but the delegate method didReceive is never called.

Notes: I’ve verified this behavior on iOS 16, 17, and 18.

Other delegate methods such as urlSession(_:task:didFinishCollecting:) do get called with the completion handler API.

This happens regardless of whether swizzling or instrumentation is involved — the issue is reproducible even with direct method implementations.

Questions:

  1. Is this the expected behavior (i.e., delegate methods like didReceive are skipped when a completion handler is used)?
  2. If yes, is there any official documentation that explains this?
  3. Is there a recommended way to ensure delegate methods are invoked, even when using completion handler APIs?

Thanks in advance!

Answered by HolgerDe in 844177022

As I understand the documentation, this is indeed the expected behavior:

By using the completion handler, the task bypasses calls to delegate methods for response and data delivery, and instead provides any resulting NSData, URLResponse, and NSError objects inside the completion handler.

See dataTask(with:completionHandler:)

As I understand the documentation, this is indeed the expected behavior:

By using the completion handler, the task bypasses calls to delegate methods for response and data delivery, and instead provides any resulting NSData, URLResponse, and NSError objects inside the completion handler.

See dataTask(with:completionHandler:)

this is indeed the expected behavior:

Correct.

To be clear, many delegate methods are called in this case; the session only skips delegate callbacks that are redundant with the results passed to the completion handler.

Is there a recommended way to ensure delegate methods are invoked, even when using completion handler APIs?

No.

Why does this matter? There are two common cases here:

  • You want to receive data incrementally, in which case you simply don’t use the completion handler methods.

  • Or you want to receive the data all at once, in which case you don’t need these data delegate callbacks.

In what situation would you need both?


This happens regardless of whether swizzling

I’m not sure where you’re going with swizzling, but I want to be absolutely clear that Apple doesn’t support you swizzling methods on our classes. If you search the forums you’ll find many cases where such swizzling has caused binary compatibility problems.

Honestly, I recommend that you avoid swizzling in general. I’ve also seen numerous cases where it causes problems for non-Apple classes. For example, I’ve seen SDKs swizzle methods on the app delegate, and that often ends badly.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

urlSession(_:dataTask:didReceive:) not called when using completion handler-based dataTask(w
 
 
Q