Networking in Swift: The Complete Guide - Digital Leaves
2334
page-template-default,page,page-id-2334,qode-social-login-1.0,qode-restaurant-1.0,ajax_fade,page_not_loaded,,select-theme-ver-4.1,wpb-js-composer js-comp-ver-5.2,vc_responsive

The Complete Guide to Networking in Swift. Digital Leaves.Hi there! This is a complete guide that will help you to master networking in Swift. We will cover from the basics to advanced stuff like communicating with a RESTful API via JSON requests and uploading files to a remote server. Let’s start!

The Basics

If you are reading this, chances are you already know the basics of networking. Basically, we have servers serving requests ro clients via a common protocol, that’s usually HTTP.

In fact, we could affirm that nowadays most modern applications communicate on top of HTTP, via direct browser interaction with an HTTP server or via RESTful requests with a backend, built on top of HTTP.

Thus, when we talk about networking here, we will refer to communications that happen on top of HTTP. That does not cover, of course, all networking scenarios, but it should serve you for 99% of the applications you will be asked to build.

Networking in Swift: The Complete Guide. Digital Leaves.So our scenario is an application you are developing that needs to communicate with the outside world via (or on top of) HTTP requests.

Alongside the request, we usually send some data and parameters. We can do it in the URI of the request, in its body, or in a set of headers that are included in the request.

There are several methods for communicating with a web server, that identify the type of request we are doing. However, usually we stick to four that form the basis of a CRUD application (Create-Read-Update-Delete):

GET Requests

These are the most usual requests you perform to a web server. Most of the requests your browser does when you visit a page are GET requests returning an HTML page that gets displayed in the browser. GET requests are always used to read information, without modifying it.

POST Requests

We use POST requests to create stuff in the server. These are the requests you use to upload information to a website, maybe sending a message via a contact form. They are usually used in the REST world to create elements or ask the server to add new resources.

Commonly, POST requests send their data in the body of the request. There are many ways in which this information can be structured (JSON, key-value pairs, etc…). The client specifies the format in which it is sending the data via the “Content-Type” header, so the server knows how to interpret and process the data.

These formats are specified with string identifiers such as “application/json” (for JSON data) or “multipart/form-data” (for file uploads in HTML forms).

We will see some examples later on.

Conversely, the client also specifies the format it expects for the information contained in the response from the server. We specify this in the “Accept” header.

PUT Requests

We use PUT requests to update information in the server. These requests are not usual in a pure browser user interaction, but we use them a lot to communicate with a RESTful backend or API.

DELETE Requests

Finally, we use DELETE requests to delete information in the server. These requests are also not usual in a pure browser interaction, but we use them a lot in RESTful requests.

What About File Uploading?

Uploading files is most commonly a special type of POST request. Instead of sending the information in the body as key-pair values, or a JSON document, data in the file is sent directly in the body of the request and codified in a special way to let the server know that we are transmitting a file.

We’ll also see some examples later. For now, let’s learn about how to do networking in Swift.

Performing Network Operations in the Background

One important thing to remember when doing networking in Swift is to always use a background queue to perform the network operation. This is because network requests usually take a long time to complete.

All user interaction and visual display of elements in an iOS App occurs in the main thread (called the “main queue” in iOS terms). As a result, if you use the main queue to perform a network operation, you will block the whole application while the network operation completes. This means that the application will become unresponsive. This is a bad user experience.

Conversely, operations that modify the user interface or interact with the user need to be performed in the main queue. Thus, we need to dispatch them in the main thread.

For this reason, you should always call all network operations from a background queue, and show results in the main queue. In Swift, we can easily do that using GCD (Grand Central Dispatching) as shown in this pseudocode schema:

In this fragment, doNetworkingOperation() and showResultsInMainQueue() are just pseudocode calls.

The real meat here is understanding how to use DispatchQueue to instantiate the global background queue and execute code asynchronously, and then when obtaining the results, showing them in the main queue. This is important specially if you are going to

Networking in Swift: URLs, URLRequests and URLSessions.

There are many libraries and frameworks out there for doing networking in Swift. Some of them are pretty good.

However, in my experience, if you want to become a pro iOS developer, it’s better to know how networking in Swift works at its core. I haven’t found an application I cannot build or a network operation I cannot perform with just some lines of code using the standard networking libraries from Apple.

There are three main entities you must be aware of when dealing with networking in Swift:

URL

The URL class represents a local or remote URI. It can be anything, from a local file accessed via “file:///…” to an HTML webpage resource like “https://apple.com” and everything in-between.

Let’s see how we can specify an URL in Swift:

Note the forced unwrapping. URL(string:) init method returns an optional because you can provide a URL string that doesn’t make any sense (such as URL(string: “1-x.y.z”).

URLRequest

URLRequest represents a proper request for a URL. As such, a URLRequest instance has a method (POST, GET, …), a body and a set of headers.

Let’s see how to define a URLRequest for a POST request sending and asking for a JSON response:

At the same time, the counterpart of a URLRequest is a URLResponse. This object is returned when you invoke any of the communication methods we are going to learn about.

URLSession

The URLSession is the class that allows us to perform a URLRequest. Most of the times, you won’t create a URLSession, as there is a singleton instance called “shared”. If you don’t need some special configuration for a concrete request, you will usually do a URLSession.shared.something().

URLSessionConfiguration

Nevertheless, there are occasions where you need to fine-tune your requests. Under those circumstances, you can define a URLSession by providing a URLSessionConfiguration. This object specifies the properties or special options you need for all the requests performed with the URLSession that uses it.

There are some already defined URLSessionConfiguration instances for most common scenarios, like default, ephemeral or background:

However, you can also define your own, and specify all kinds of properties such as the cache size, fixed headers or the timeout interval:

For a complete list of the properties you can tweak, visit Apple’s documentation.

Creating a URLSession With a URLSessionConfiguration

Finally, this is how you can create a URLSession using a custom configuration:

Nonetheless, 99% of the time you can stick to URLSession.shared for most of your networking in Swift.

Next, let’s see how to perform requests and process the results.

Basic Networking in Swift: Downloading a Webpage

The most basic step to learn networking in Swift is probably downloading the HTML code for a website. This is just a basic GET request to an HTML resource.

In Swift, we can do it thanks to the dataTask method of URLSession:

First, we create an URL instance for Apple’s website, and call it httpURL.

Then, we perform a GET request creating a dataTask on the shared instance of URLSession. This only creates and defines the task, but doesn’t actually performs it. To run the task and perform the request, you need to call resume on it.

Testing Networking in a Playground

To test the code for networking in Swift inside a playground, you  need to add some code to tell the Playground to wait for the -potentially- long network operation. Otherwise, your requests won’t work:

Make sure to include that code at the top of your Playground when testing these examples.

Intermediate Networking in Swift: RESTful Requests

Downloading a website is nice, but probably not very useful for most real app development scenarios. Most probably, the majority of your app requirements will involve communicating with a RESTful API. Furthermore, the vast majority of those APIs will use JSON for back and forth communication. Thus, it’s an essential topic if we want to master networking in Swift.

Thus, let’s have a look at how to perform RESTful requests to the API of a backend, transmit JSON data and getting back a response in JSON too.

For the rest of this section, we’ll suppose that we are invoking the methods that perform the requests in a background queue, so we will return our responses in the main queue.

A GET Request

Let’s start with a GET request. Instead of invoking dataTask with a URL, we’ll generate a URLRequest from that URL and invoke dataTask on that URLRequest.

In order to avoid building or setting up a web server, we will use the free service httpbin.org, that allows us to send RESTful requests and receive results to check that we are sending the right data in the right way.

Thus, for our GET request, we will use the “/get” endpoint, and add some parameters in the URL (like foo=bar).

First, we create a URL with the httpbin.org/get endpoint, adding some parameters to the URL. Next we create a URLRequest with that URL. Creating a URLRequest instead of using the URL directly in dataTask will allow us to modify some properties of the request, like the headers to include.

In this case, we will be sending JSON data and expect to receive JSON data too. That’s why we set both “Content-Type” and “Accept” headers to “application/json”.

Then, we use this URLRequest to call dataTask on the shared URLSession. The dataTask method has an asynchronous completion block that receives the response with three properties (all of them optionals):

data

The data of the response, if the request was successful and the server included some data in the response.

response

A URLResponse object with useful information like the returned status code, the response headers and some other information.

error

If the request resulted in an error (i.e: because the server was down or the request was incorrectly built) we will get an error. This error allows you to debug what caused this condition and hopefully correct it.

Finally, notice how we use the jsonObject:withData: method of JSONSerialization to transform the received data into a valid JSON object we can use.This JSON object will be, depending on the server’s answer, a Dictionary (JSON object) or an Array (JSON array).

The response from httpbin.org is an object with information of the request itself. Thus, if we perform this request, we get the following information:

Next, let’s have a look at a POST request. PUT and DELETE requests are pretty similar, only the meaning changes.

A POST Request

For our POST request, we will send a JSON object (represented as a Swift Dictionary) to httpbin.org. The endpoint we will be using is httpbin.org/post?param1=value1. I have added query parameters so you can see the difference between them and the data in the body of the request.

Let’s start by defining our URL and URLRequest objects:

Next, we create the dictionary with our parameters and set the URLRequest’s httpBody property (that sets the data for the body). In order to do this, we need to transform the dictionary to a Data binary format.

We can achieve this by using JSONSerialization’s data:withJSONObject:options:. As this method can potentially throw an exception, we

Finally, postRequest contains the body with the information expressed as JSON data. Let’s call dataTask and see the results:

The results

If everything goes well, the results will indicate that we sent the param1=value1 parameters as query arguments and our dictionary in the “data” section of the body.

You will notice there’s an empty “files” section in the response. This property refers to your usual “upload file” request from an HTML “file” input field in a form. Sometimes, you need to communicate with an API that expect you to send a file in this format. In the next section, we are going to explore how to do just that.

Advanced Networking in Swift: Uploading Files

There is just one last thing for mastering networking in Swift: uploading files.

There are many resources out there showing you how to “upload” a file as part of the body data of a POST request. However, sometimes you need a good-old file upload, whose contents are uploaded as a file, not as base64 data in a JSON object.

There’s an uploadTask in URLSession that might make you think it’s been designed precisely to upload files. Nevertheless, this method is just a variant of dataTask that allows for background uploading of information. From Apple’s documentation:

Unlike data tasks, you can use upload tasks to upload content in the background. (For details, see URL Session Programming Guide.)

Thus, in order to properly upload files using swift, we need to massage the body contents a bit.

Building a body for uploading a file

In order to upload a file properly, we need to construct the body of the request in certain format.We need to generate a boundary identifier that will allow us to “separate” the different parameters and files. This identifier can be any random string as long as we use it consistently throughout the body.

This function allows us to easily generate a boundary identifier:

UUID is a class that generates unique identifiers (UUIDs). Then we will build our body with the following schema:

This is the method for doing so:

The appendString method is just a useful extension to add the bytes of a string to a previously existing data:

Uploading the Data as a Proper File

Finally, once we have our dataUploadBodyWithParameters method to build the body, we just have to assign that as the request’s body.

In your app, you might want to enable UIApplication.shared.isNetworkActivityIndicatorVisible when you are about to perform a network operation. It enables the spinning wheel in the status bar of the iPhone that indicates the user that the device is accessing the network.

Once the network activity has expired, don’t forget to set it to false. Note that you cannot do this in the Playground, only in a real app.

Uses for uploadTask

We said before that uploadTask is similar to dataTask, but applies to background tasks. What does that mean? In summary, when an app goes to the background (i.e: if the user hits the Home button), any networking task you have active will suspend automatically.

However, performing long background operations is a common requirement that you will face sooner or later when building an application. Imagine you are building a social network iOS app similar to Instagram. One of the main features of the application will be uploading photos to the backend.

Of course, you can’t expect the user to wait while you are uploading a 1Mb photo, specially on a slow connection (i.e: 3G). Instead, you need to allow the networking operation to continue while the user suspends your app and moves to a different one while the picture is uploading.

Background-Wise Networking in Swift

In order to perform this background operation, first you need to define a UIBackgroundTaskIdentifier that will identify the background task. Then, before you start the networking operation, you call UIApplication.shared method beginBackgroundTask to start the background task.

Henceforth, iOS will give you a window of up to 10 minutes to perform the background task (i.e: the networking operation).

Once finalized, or in any error situation that might cause it to exit, you must remember to invoke UIApplication.shared method endBackgroundTask and set the task identifier to invalid.

A Simple Example of Launching a Background Networking Operation

Here, uploadImageWithData:completion: is a method that encapsulates the upload file functionality we described previously.

Where To Go From Here

To summarize, in this “Networking in Swift: The Complete Guide” tutorial, we learned how to master networking in Swift, from the very basics to the most advanced stuff. In a series of tutorials to be released soon, I will address more complex topics like building a RESTful client from scratch to communicate with the API of a backend.

Did you enjoyed this networking in Swift tutorial? Is there anything missing? Let us know in the comments!

Before you continue...

Hi there! I created the Digital Tips List, the newsletter for Swift and iOS developers, to share my knowledge with you.


It features exclusive weekly tutorials on Swift and iOS development, Swift code snippets and the Digital Tip of the week.


Besides, If you join the list you'll receive the eBook: "Your First iOS App", that will teach you how to build your first iOS App in less than an hour with no prior Swift or iOS knowledge.

I hate spam, and I promise I'll keep your email address safe.