Can I somehow do a synchronous HTTP request via NSURLSession in Swift
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
URLSession does not offer a normal synchronous API, and that is intentional. Network I/O is slow and unpredictable, so Apple’s networking stack is built around asynchronous execution rather than blocking the calling thread.
If what you really want is sequential-looking code, modern Swift already gives you that through async and await. In most cases, that is the right replacement for the old idea of a synchronous request.
Use the standard asynchronous API
The classic URLSession style uses a completion handler:
This is the design the framework expects. The call returns immediately, and the response arrives later through the callback.
Prefer async and await in modern Swift
If you want code that reads top to bottom, use Swift concurrency instead of trying to force URLSession into a blocking API.
This feels synchronous from the caller's point of view, but it does not block the main thread.
You can block a thread, but it is a workaround
If you truly must bridge async networking into a blocking API, a semaphore can do it. This is usually a legacy workaround and should not be your default design.
This blocks the current thread until the request finishes. It should never be used on the main thread of an iOS app.
Why synchronous blocking is usually the wrong goal
Blocking network code creates several problems:
- the UI can freeze
- cancellation becomes awkward
- timeouts and retries become harder to model
- deadlocks become easier to introduce in wrapper code
The requirement often turns out to be "I want simple control flow," not "I want to block a thread." async and await solve the first problem without creating the second.
When a blocking wrapper may be acceptable
In a small command-line tool or test harness, blocking a background thread can be tolerable. In an iOS app, especially in UI code, it is almost always the wrong tradeoff.
If older APIs in your codebase expect a synchronous result, the better long-term fix is usually to push the async boundary upward and let callers become async too.
Common Pitfalls
The most common mistake is using a semaphore-based wrapper on the main thread. That can freeze the app and trigger watchdog termination.
Another issue is treating "sequential-looking code" as proof that you need synchronous networking. In Swift, structured concurrency already gives you sequential control flow without blocking.
Developers also sometimes expose blocking networking APIs from reusable libraries. That makes it harder for callers to cancel work or integrate with concurrency later.
Finally, do not forget that URLSession callbacks and async APIs already handle networking in the intended platform model. Fighting that design usually makes the code worse, not simpler.
Summary
- '
URLSessionis designed for asynchronous networking, not synchronous blocking.' - Use completion handlers or, preferably,
asyncandawaitfor sequential-looking code. - A semaphore can simulate synchronous behavior, but it is a workaround.
- Never block the main thread waiting for a network response in an iOS app.
- If synchronous networking seems necessary, reconsider the API boundary first.
Related reading
- Can I use AWS Certificate Manager certificates for API Gateway with Custom Domain Name
- Can I use Kafka queue in my Rest WEBSERVICE
- Can I write a program to see if a table exists in YugaByte's YCQL (Cassandra) api?
- Can not set field to com.sun.proxy.Proxy
- Can I underline text in an Android layout?
- Can I underline text in an Android layout?
- Can .select() on both traditional and ZeroMQ sockets?
- Can talk to Zookeeper but not to the message brokers

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.