NSURLConnection and sendAsynchronousRequestqueuecompletionHandler - does the completion block run in the main thread
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
The completion block for sendAsynchronousRequest:queue:completionHandler: runs on the NSOperationQueue you pass in. It does not automatically run on the main thread unless the queue argument is specifically NSOperationQueue.mainQueue().
The Short Answer
This method has two separate concerns:
- the network request itself happens asynchronously
- the completion handler is dispatched onto the operation queue you provide
So the answer is simple:
- pass the main queue, and the completion block runs on the main thread
- pass a background queue, and it runs on that queue instead
That is why UI updates are only safe without extra dispatching when you intentionally use the main queue.
Objective-C Example
Because the queue is [NSOperationQueue mainQueue], the block runs on the main thread.
If you use a custom queue:
Now the block should be treated as background work.
Why This Matters
The queue choice determines what is safe inside the completion block.
If the completion handler runs on the main thread, you can update labels, image views, and other UIKit objects directly. If it runs on a background queue, touching UIKit there is a bug waiting to happen.
A common pattern is:
- receive data on a background queue
- parse or transform it there
- dispatch UI changes back to the main queue
That keeps the interface responsive and still respects UIKit's thread-safety rules.
Example of Background Work Followed by UI Update
This is the safe pattern when the completion block itself is not already on the main queue.
Legacy Context
NSURLConnection is legacy API and has been replaced in modern code by NSURLSession, which gives better control over sessions, tasks, delegates, and background transfers. Still, the threading rule in this old method is clear and useful when maintaining older applications: the completion handler follows the queue you supplied.
One practical debugging trick is to log [NSThread isMainThread] inside old callbacks before touching UI code. In legacy applications, that quick check often explains crashes or visual glitches that only happen after networking completes.
Common Pitfalls
- Assuming "asynchronous" automatically means "main thread callback."
- Updating UIKit objects from the completion block when a background queue was passed.
- Forgetting that the queue parameter controls completion delivery, not just internal request execution.
- Using
NSURLConnectionin new code whenNSURLSessionis the modern replacement. - Passing a custom queue and then debugging random UI issues caused by off-main-thread updates.
Summary
- The completion handler runs on the
NSOperationQueuepassed to the method. - It runs on the main thread only if you pass the main queue.
- UI updates are safe only when the callback is on the main thread.
- Background queues are useful for parsing or processing response data.
- In modern code, prefer
NSURLSession, but the same threading discipline still matters.

