URLSession to Electrons: How Networking works on iOS
A theoretical deep-dive into how the internet happens via your iPhone
One of the reasons I reckon I’m a decent writer is that I can remember what it’s like to be very junior. Noob-y mistakes were my bread and butter. I hailed from the “no question is a stupid question” school of thought, and had zero filter when I felt blocked.
These traits combined to make me very annoying to Josh and Si, our resident seniors. My relentless requests for help were invariably met with some variant of:
“You forgot to assign the UITableViewDataSource, didn’t you?”
“You didn’t set translatesAutoresizingMaskIntoConstraints = false”
“You have to call .resume() on that URLSessionDataTask”
This wistful nostalgia trip got me thinking.
What actually happens when you call .resume() on a URLSessionDataTask?
The subsequent rabbit hole is quite fascinating, and required reading if you never stopped to wonder how literally the entire internet works.
So today is a theory lesson + case study.
We’re covering the conceptual model underpinning the vast network of networks that make up the internet.
Along the way, we’re going to follow the unassuming URLSessionDataTask as it traverses each layer of abstraction: from your app’s API request, to system frameworks, into the kernel, via drivers into the radio hardware, and finally out into the physical world as electromagnetic radiation.
Sponsored Link
Lessons Learned from Security Incidents in Mobile Apps
Join Security Researcher and Pentester, Jan Seredynski, on a live stream on May 12 as he dissects recent real-world security incidents in banking, food delivery, and e-commerce. From face verification bypass to location spoofing, he'll break down the anatomy of a breach and what teams can do differently to address them.
Contents
What is the Internet?
The internet is a global system of interconnected computer networks, with 2 major types of entity:
End systems (a.k.a. “hosts”). This might be an iPhone, a server in a data centre, or perhaps a very clever fridge.
The network core. This is a mesh of routers, packet switches, and IXPs (internet exchange points) that play pass-the-parcel with packets of data.

This network core includes the global backbone of the internet: an interconnected web of physical infrastructure like copper wire, fibre optic cable, and undersea cables carrying data between networks.
This lowest level of infra is operated by friendly, totally non-evil companies such as Verizon, AT&T, and Google. The interconnectivity is key: the internet as we know it works because these companies all agree to route each other’s traffic.

The networks are compatible because they all speak to each other via IP, the internet protocol. This is the most fundamental thing to understand. A protocol is simply a specified format for sending and receiving messages. These formats are agreed via an “RFC” process run by a shadow cabal, the Internet Engineering Task Force.
Routers forward packets between each other as data traverses this physical system of cables, fibre, and radio links to their destination; from your iPhone in the UK, through to a VPN server in Sweden, down to an edge cache in Germany to retrieve your favourite scheiße video (and back).
To understand how we go from URLRequest to a streamed .mp4, we follow the classic five-layer Internet model:
application
transport
network
link
physical
The layered model is all about abstractions.
The application layer worries not about the underlying orchestration of packet encapsulation and transport links. It might as well be magic. Who cares? Data go into pipe, data come out of pipe.
This “who cares” powers the entire global software ecosystem, preventing lowly web developers going insane when confronted with manmade horrors beyond comprehension (like ethernet ports).
Abstraction saves you from understanding implementation details of each layer. You just need to know the protocol, that is, the format of data in and out. Abstraction is everywhere. It’s why you’re able to ship profitable SwiftUI apps without understanding the low-level process memory management done via a red-black tree inside the XNU kernel. Whoooooo. Cares.
Let’s investigate each layer, step-by-step, looking at real code to understand as we go.
URLSession and the Application Layer
The application layer is where all the interesting stuff around the network can be done. It contains HTTP, DNS, cookies, caches, configuration, and everything else you actually touch in your day-to-day.
URLSession
URLSession is your entry-point into this world. To handle a run-of-the-mill network request, you’ll create a session, configure it, set up a task, and kick it off with resume().
p.s. I am using the handy open-source FoundationNetworking library here, which relies on curl rather than CFNetwork.
Internally, URLSession uses both Grand Central Dispatch and NSOperation to avoid data races, using GCD queues to protect its internal state, and operations to handle URLSessionDelegate callbacks.
Resuming the DataTask
Individual requests are created and executed using a URLSessionDataTask. This calls into the underlying implementation library (curl or CFNetwork) and feeds data back to the session. The task tracks its state, counts bytes, and finishes with either a URLResponse or an Error.
This data task gives devs the opportunity to configure the request before work begins. It inits in a suspended state, kicking off when resume() is called.
The async/await form conveniently handles both task creation and resume() internally. It’s truly nothing special, wrapping the O.G. dataTask(with: URLRequest) function in withCheckedThrowingContinuation.
HTTP, DNS, and Cookies
In the application layer, network requests often have a human-readable format, such as the ubiquitous HTTP request.

You can trivially instrument the application layer yourself: via Charles Proxy, Proxyman, or on the web, by right-clicking and tapping “inspect element”, then looking at the “Network” tab of the site debugger.
DNS is a distributed dictionary that maps URL hostnames to IP addresses. Caches on your URLSessionConfiguration help decide whether your request even needs to hit the network. Cookies attach metadata to stateless requests to help our server maintain a consistent user state. If you want a stateless request, you can use an ephemeral session configuration.
The curl and CFNetwork libraries handle lower-level details in the application layer such as multiplexing, which combines multiple HTTP streams onto the same TCP connection (see below), saving energy by reducing connection overhead.
Ultimately, these lower-level libraries run syscalls into the kernel such as connect, socket, send, and recv. This brings us down to the next layer.
The application layer is where you’ve spent most of your life.
Paid members may step into the abyssal depths of syscalls, TCP/IP, packet switching, buffering, custom transport layers, IEEE 802.11, 5G, datagrams, packets, radios, and how your URLSession ultimately turns into electromagnetic radiation.
Paid members also get Elite Hacks, advanced concurrency training, and my free articles one month early 🚀







