Alamofire iOS Advanced Techniques

Amr El-Sayed
Mac O’Clock
Published in
18 min readJun 15, 2020

Alamofire is an essential networking tool for any iOS developer to have under their belt. The framework is elegantly written entirely in Swift.

The framework itself serves as an abstract layer of functionality on top of Apple’s existing networking stack. So, your existing knowledge of the iOS networking landscape is still valid. And, you’ll build on top of it.

In this Alamofire tutorial for iOS, you’ll explore the following topics:

  • Building a scalable pattern for organizing your networking stack.
  • Handling different error responses.
  • Dealing with authentication APIs.
  • Setting a retry policy for request failures.
  • Dealing with different request types.
  • Tracking internet reachability status.

Getting Started

Start by downloading the project materials from this repository.

Open DnDRealm.xcworkspace in the starter project. Build and run.

Listing monsters, and searching for equipment. An error alert appearing when select an item

The app you’ll build lets you search for Dungeons and Dragons equipment and monsters using DnD API. Also, the app will feature fetching monster images using Imgur API. And, you’ll implement images upload.

Ready to explore the Dungeons and Dragons realm? Time to dive in!

Flying owl and pop-up chat with the sentence Don’t Worry, Alamofire to rescue you.

Understanding Routing Requests

As an app’s networking endpoints grow in size, the number of lines of code grows along with it. The router pattern is an important part of organizing your networking stack.

A router is a type that defines routes or URLRequest components. URLRequest represents information about its Request, such as URL, parameters, headers, method types and policies. As shown below:

The Request and URLRequest relationship

Alamofire provides URLConvertible and URLRequestConvertible protocols to simplify the magic of routing.

Creating the DnD Router

Currently, the HTTP requests for fetching and searching use string endpoints. That’s messy. Add a router to encapsulate DnD APIs routes.

In Routers group, create a new file named DndRouter.swift. Then, add the following to the file:

The enum defines two cases, each for a specific route:

1. monsters fetches the monsters list.
2. equipment(name:) searches for equipment by name.

Specify the URL paths for each case by adding the following to DnDRouter:

Here’s the code breakdown:

1.baseURL defines the DnD API’s starting endpoint.
2. path specifies the path components for each route.

The code above gives the router its endpoint information, but it’s missing an HTTP method for each case.

Next, add import Alamofire to the top of DndRouter.swift. Then, add the following to DnDRouter:

Since both routes are requesting data, you can use a fall-through switch statement. Both cases will return an Alamofire HTTPMethod.get as their request type. Now, add the route parameters to DnDRouter:

The monsters route doesn’t have any parameters, indicating the API doesn’t require any. The equipment, however, needs a dictionary with a key-value pair as specified in DnD API docs.

Now the router has all its components, you can define its routes’ URLRequest.

Add the following extension at the bottom of DndRouter.swift:

The code above constructs URLRequest as follows:

  1. It conforms the router to URLRequestConvertible and implements its required method asURLRequest().
  2. Then, it constructs the route URL by appending baseURL with the route path component.
  3. It defines a URLRequest instance using the route URL.
  4. Then it assigns the URLRequest.method property with the route method.
  5. Next, it encodes and embeds the route parameters into the URLRequest instance. URLEncodedFormParameterEncoder encodes the passed parameters into a URL-encoded string.
  6. Finally, it returns the encoded URLRequest.

Now, the DndRouter routes are ready to be attached to a Request.

Open MonstersTableViewController.swift. Replace the following code in fetchMonsters():

With:

Then, in searchEquipment(with:), replace:

With:

DnDRouter achieves a separation of concerns in your networking stack.

Here’s a diagram illustrating the DnDRouter pattern.

The DnDRouter pattern

It shows how DnDRoute constructs monsters and equipment routes to be attached to a Request for heading to the network.

Parameter Encoding

Alamofire supports any Encodable as request parameters.

It provides two ParameterEncoder conforming types:

  • URLEncodedFormParameterEncoder: Encodes values into a url-encoded string. Its destination decides where to set this encoding result:
    * queryString: The query of the request’s URL.
    * httpBody: The HTTP body of URLRequest.
    * methodDependent: It uses queryString for GET, HEAD and DELETE, but httpBody for others.
  • JSONParameterEncoder: Encodes Encodable values using Swift’s JSONEncoder. It sets the result in the HTTP Body of URLRequest.

Both types set the URLRequest’s Content-Type header parameter if it’s not already set.

Creating the Images Router

Encapsulate the Images API‘s routes in a separate router.

Now, create a new router to hold the images searching route.

In Routers group, create a new Swift file named ImagesRouter.swift. Then, add the following to the file:

ImagesRouter defines images(query:) route for images search using query value.

Next, define the path URL. Add the following in ImagesRouter:

It’s a GET method. Add the following:

Then, define the API parameters. Add the following:

As you did for DNDRouter, add the following extension at the bottom:

Finally, attach images(query:) route to a request.

Open ImagesCollectionViewController.swift, replace fetchImages():

With:

Note: The Dragons keyword increases the probability of getting the search result.

Build and run. You’ll see no differences. :]

Listing monsters, and searching for equipment. An error alert appearing when select an item
Swift icon speaking to a bug: it asks Tidy code, right?, the bug replies: I hope you fix this alert

Serializing Responses

Before you fix the response error in the images screen, you need to parse and convert it into a suitable format. This’s the response serializer mission.

Fortunately, Alamofire provides three ResponseSerializer conforming types:

  • DataResponseSerializer: Useful for customized data handling. It’s used in responseData(queue:completionHandler).
  • StringResponseSerializer: Uses String.Encoding to parse data to String. responseString(queue:encoding:completionHandler:) uses it.
  • DecodableResponseSerializer: Parses data into specific Decodable types. It’s the serializer for responseDecodable(of:queue:decoder:completionHandler:).

Here’s a diagram to show the various components working together:

The response handlers interactions in the request cycle

After routing a request to a server, response handlers receive and serialize the response data.

Creating an Error Response Serializer

The Imgur API has two possible responses: Success or Error, each with a different model.

By checking fetchImages() from ImagesCollectionViewController, you’ll find:

1. Success response: responseDecodable(of: Images.self) serializes it. Additionally, it settles for case let .failure(error) to show an alert in case of any failure.
2. Error response: There is no handler to consider its serializing.

Here’s the error response:

Note: The starter project provides:

  • ImagesErrorResponse: A decodable struct for mapping the error response above.
  • ResponseError: An enum that conforms to Swift’s Error protocol to represent your custom error.

This is a good chance to create your ResponseSerializer for error handling. Besides the API error response, you’ll also handle the connectivity errors.

In Serializers group, create a new Swift file named ErrorResponseSerializer.swift. Then add the following at the top of this file:

The code above creates ErrorResponseSerializer that conforms to ResponseSerializer and implements its serialize(request:response:data:error:).Then it returns a ResponseError as its generic type.

For handling the connectivity errors, add the following at the start of serialize(request:response:data:error:):

This guard statement guards against the chance of no return data due to internet connectivity or timeout errors.

Alamofire serializers already do much of the heavy lifting. This is a good time to ask them for help in serializing the API error response.

Add the following at the end of serialize(request:response:data:error:):

The code above:

  1. Uses Alamofire’s DecodableResponseSerializer to parse the response using ImagesErrorResponse. Keep in mind, pass nil for error in serialize(request:response:data:error: otherwise, it’ll throw an error without trying to decode the response.
  2. Checks and returns the appropriate ResponseError, either authentication or server error.

Note: The starter project defines an Int extension with isAuthenticationErrorCode() for matching authentication response codes 401 and 403.

Now, ErrorResponseSerializer is ready for attaching to the Request cycle and serializing such responses.

Open ImagesCollectionViewController.swift and add the following at the end of the Alamofire request in fetchImages():

This code adds an additional response handler to the Request instance. It’ll handle the error response if it occurs.

Note: showError(_:) is defined at the bottom of ImagesCollectionViewController. It shows a suitable AlertViewController corresponding to the ResponseError type.

Before you run, delete the blind failure handling in .responseDecodable(of: Images.self). Replace:

With:

Build and run to see the error handling in action.

Listing monsters. An Authentication required alert appearing when select an item

Then, turn off your internet connection and choose any monster to test how connectivity errors are handled.

Listing monsters. Check your internet connection alert appearing when select an item
Bugs walking and say these sentences: Great handle!, Authentication required!!, and Didn’t see images yet!

Understanding API Authentication

Keeping their data secure is a chief concern of data providers. The three major methods of adding security to an API are HTTP Basic Auth, API Keys and OAuth.

Imgur uses OAuth 2.0. It’s fundamentally the more secure option for authentication and authorization.

The Imgur OAuth 2.0 stages

The figure above illustrates the main stages of OAuth 2.0. To dive deeper into these stages, the diagram below gives you a focused idea of what’s in store when authenticating with the Imgur API:

The client makes an authorization request for an access token and a refresh token. Using the access token, the client is either able to retrieve resources from the resource server with a valid token. In the case of an invalid access token, the resource server returns an error. In that case, the client would use the refresh token to retrieve new access and refresh tokens.

Note: For more information about OAuth 2.0 check out OAuth 2.0 with Swift.

Registering the App With Imgur

Every OAuth 2.0 service requires you to register your app at some point. Open Imgur Registration to register an account. Then, click here to register an app on their developer portal.

Use the following information to register your application:

  • Application name: DnDRealm.
  • Authorization type: OAuth 2 authorization with a callback URL.
  • Authorization callback URL: rwdnd:\.

Then, enter an email.

Once completed, you’ll see a screen like this:

Imgur developer portal after register the application. It contains ClientID, and Client secret fields

Copy your Client ID and Client secret into Authentication/AuthenticationKeys.swift as follows:

Cool. :] You’re ready to begin the authorization cycle.

Swift icon says: Don’t worry the starter project gives a hand on time

Authorizing the User

The authorization URL lets the user to login and give permissions to the registered app. Define it as per Imgur API documentation.

Now, open ImagesRouter.swift and add the following below baseURL:

Next, open ImagesCollectionViewController.swift. InpresentAuthenticationAlert(with:), add the following code underneath
// TODO: Login Action:

That’ll open the browser with authorizationURL when the user taps the alert’s login button.

Build and run. Tap on a table view cell. An alert pops up. Tap the login button. The following will appear:

Safari with the Imgur login screen

The app redirects you to the Imgur authentication page. Log in with your account.

Once you’ve successfully logged in, an alert will ask you if you want to open the app. Tap Open. :]

Safari with the Imgur login screen, showing an alert to Open in DnDRealm

You’ve achieved step one of the Imgur API authentication flow! The starter project has handled the returned tokens and completed step two for you. :]

Note: The starter project provides:

  • TokenHandler protocol: It extracts the access and refresh tokens from the callback URL. After that, it stores them in Keychain.
  • Authenticator protocol: It’s responsible for retrieving and refreshing the access token.

Note: For more information on dealing with Keychain check out the Keychain Services API Tutorial for Passwords in Swift.

Working With a Request Interceptor

Alamofire’s RequestInterceptor protocol is composed of RequestAdapter and RequestRetrier protocols. They can play a big part in your app authorization cycle.

The relation between RequestInterceptor and both RequestAdapter and RequestRetrier

RequestAdapter inspects and mutates each URLRequest before sending it over the network. Therefore, it’s a suitable place to inject the authorization header into URLRequest. Here’s a diagram illustrating how it interacts in the Request cycle.

The RequestAdapter interactions inside the request cycle

Per adaptation Success, RequestAdapter appends an extra URLRequest and URLSessionTask to the request’s requests and tasks properties

Adding the Authorization Header

The authorization request header contains the credentials to authenticate a user with a server. So here you’ll add the access token while adapting the request.

Under Interceptors group, create a new Swift file named ImagesRequestInterceptor.swift.

Add the following:

Here you:

  1. Create your RequestInterceptor class, conforming to: --*RequestInterceptor to implement RequestAdapter.adapt(_:for:completion:). RequestAdapter executes this method before sending URLRequest to the server.
    * Authenticator. The protocol that provides the authentication access token.
  2. Then define a new URLRequest instance to be the manipulated.
  3. Check if there is a stored accessToken inside the app if the user successfully logged in before.
  4. Next, add the accessToken in the URLRequest’s authorization header using HTTPHeader.authorization(bearerToken:).
  5. Then send the modified URLRequest over the network.
  6. If there is no accessToken, abort the Request with an authentication error.

Note: Alamofire’s HTTPHeader provides authorization types that match to the following authentication approaches:

  • HTTP Basic Auth: .authorization(username:password:)
  • API Keys: .authorization(_:)
  • OAuth Token: .authorization(bearerToken:)

Guess which component handles the authentication error that appeared in the sixth step of the code above? That’s right, it’s your ErrorResponseSerializer handler!

Handling Adaptation Error

The adaptation error is that error occurs during the execution of adapt(_:for:completion:). Now, you’ll handle this error.

Open ErrorResponseSerializer.swift, add the following code to the top of serialize(request:response:data:error:):

The code above checks and returns the adaptation error.

Finally, inject ImagesRequestInterceptor into the Request execution cycle.

Open ImagesCollectionViewController.swift, replace the following inside fetchImages():

With:

Build and run. You’ll to steps three and four in the authorization cycle complete.

Empty green images appearing when select monster from the list
iPhone saying: I got a response, and it is going to hit the bug that says: Authentication required!!

Requesting Retrier Role

RequestRetrier protocol can retry a request that encountered an error. Therefore, it’s a suitable place to refresh the access token when being invalidated.

Below is a diagram showing the interaction flow of RequestRetrier:

The RequestRetrier interactions inside the request cycle

Retrying a request appends a new URLRequest to its requests property.

RequestRetrier fires within a possible set of errors:

  1. URLRequestConvertible returns an error when called.
  2. RequestAdapter fails during adaptation.
  3. URLSessionTask completes with errors for various reasons such as networking availability or cancelation.
  4. Response handlers produce error due to invalid response or parsing.

Note: RequestRetrier can also produce errors, which do not trigger the retry action.

Refreshing the Access Token

When the access token expires or becomes invalid, it’s time for the refresh token to get a new one. Refresh tokens carry the information necessary to obtain a new access token without prompting the user.

Now, you’ll implement your RequestRetrier for refreshing the access token.

Open ImagesRequestInterceptor.swift, add the following to ImagesRequestInterceptor:

Breaking this down, you get the following:

  1. RequestRetrier executes retry(_:for:dueTo:completion:) when errors occur.
  2. The guard prevents Request from retrying if it doesn’t bypass the following conditions:
    * lastProceededResponse != request.response: Prevents the body from multiple executions for the same response instance. Notice RequestRetrier may execute many times for the same response. For example, an authentication response error and serialization error occur for the same response. As a result, Alamofire fires their RequestRetrier twice, one per error.
    * request.retryCount < retryLimit: Limits the maximum number of Request retries.
    * let statusCode = request.response?.statusCode and statusCode.isAuthenticationErrorCode(): Ensure it’s an authentication error.
  3. It keeps the reference of the last processed response, as the guard above checks for it.
  4. It’s an authentication error. Therefore, it calls Authenticator.refreshToken(completion:), which achieves the following:
    * Sends a Request for refreshing the invalid access token.
    * Stores the new access token to be ready for use.
  5. As a result of refreshing the access token process, it decides to either RetryResult.retry or RetryResult.doNotRetry.

Here’s a diagram illustrating the possible values of RetryResult.

The possible values of RetryResult are: retry, retryWithDelay, doNotRetry and doNotRetryWithError

Note: Alamofire includes a built-in RetryPolicy interceptor. It enables easy retry when requests fail due to a variety of common network errors.

Finally, to ensure that all are well-suited, move refreshToken request’s information from Authenticator.refreshToken(completion:) to ImagesRouter.

Open ImagesRouter.swift, add the following case to ImagesRouter:

Then, define its path. Add the following code to path:

It posts data, so add the following to method:

Next, construct its parameters as follows:

Finally, open Authenticator.swift and replace the following code:

With:

Good job! You’ve completed the authorization cycle.

Build and run.

Empty green images appearing when select monster from the list
Bug icon says: Still, didn’t see images!, and swift icon replies: But, the authorization cycle is done!

Understanding Request Types

Alamofire’s Request has different types to fit different purposes. Each type is encapsulated by a particular class with unique properties and functionalities as shown below:

The hierarchy of Alamofire different request types

Alamofire’s Request has three fetching data subclasses, such that DataRequest accumulates response data into memory, DataStreamRequest streams the data, but doesn’t accumulate it, and DownloadRequest downloads the data to disk. In addition, UploadRequest is a subclass of DataRequest to upload data, files, or InputStream to a server.

These subclasses act as a wrapper for URLSessionTask. Each Request keeps a copy of URLRequests and URLSessionTasks that includes both the initial created from the parameters, as well as the created by RequestInterceptor.

Note: See Apple Documentation for more information on URLSessionTask and its types.

Streaming Images Using DataStreamRequest

Alamofire’s DataStreamRequest is suitable for long-lasting server connections that receive data over time. It never accumulates data in memory or saves it to disk. You’re about to use it for streaming the images.

Now, check ImagesCollectionViewController.fetchImages(), you’ll find it saves the response in items: [GalleryItem].

This GalleryItem represents an image, so converting it to a self loadable resource enables Alamofire to attach it to a Request directly as URL.

Next, open GalleryItem.swift and add the following extension after
// MARK:- Alamofire URLConvertible:

The code above defines the GalleryItem URL by conforming to URLConvertible as discussed in the Understanding Routing Requests section. Simply put, this returns a GalleryItem.url for URLConvertible.asURL().

Now, items is ready for streaming.

Open ImagesCollectionViewController.swift, add the following to streamImages():

The code above:

  1. Initializes a DataStreamRequest for each GalleryItem in items.
  2. Then it validates the response so:
    * HTTPURLResponse.statusCode is within the 200..<300 range.
    * The Content-Type header matches the request’s Accept value.
  3. Next, it adds a responseStream(on:stream:) handler, which is repeatedly called as data arrives.
  4. Then, for the valid data responses, it invokes GalleryItem.appendData(_:), which achieves the following:
    * It appends the data inside each GalleryItem instance.
    * Next, it fires GalleryItem.responseStream closure. This allows any instance of listening for this stream of data.
    Check ImageCollectionViewCell.monitorDataStream(for:) that listens and displays this stream.

Build and run. The images are downloading. :]

Because the images are fetched randomly, the same image may be fetched many times. What if the same image is fetched again? Will it stream again?!

Yes, it will. However, Alamofire’s CachedResponseHandler can give you a hand.

Caching Images

Response caching has a big impact on Apps performance. It efficiently stores and reuses previously retrieved responses to serve their future requests.

Alamofire provides ResponseCacher which conforms to CachedResponseHandler. It makes it easy to control the caching behavior.

To overcome the image multiple-time streaming, cache its stream response.

Now, open ImagesCollectionViewController.swift. Inside streamImages(), add the follwing right below .validate():

This single line code caches the images by adding Request.cacheResponse(using:) with Behavior.cache.

The possible Behavior values for ResponseCacher. cache, modify, and doNotCache

Here are the possible Behavior values:

  • cache stores the response.
  • modify(_:) modifies the response before storing it.
  • doNotCache prevents the response from being stored.

Note: For information about the caching rules, check Apple Documentation.

Build and run for one-time streaming.

yeti with search icon says: I can see green arrows! For what?

Uploading Images Using UploadRequest

Are you interested in adding images to your Imgur profile? You’ve already appended each GalleryItem’s streamed data, which means you’re ready to upload them.

Now, you’ll define the upload route.

Open ImagesRouter.swift. Add the following case to ImagesRouter:

Then, add the following to path:

Add the following to method:

Finally, add the following to parameters:

Now, define a method to upload a GalleryItem using this route.

Open ImagesCollectionViewController.swift. Add the following extension after // MARK: — Alamofire UploadRequest:

The code above defines upload(_:at:) to upload a GalleryItem.

Here’s a breakdown:

  1. Instantiates an UploadRequest instance to upload the GalleryItem.data to the ImagesRouter.upload route.
  2. Listens for errors using ErrorResponseSerializer.
  3. In case of error and before showing it, confirm that GalleryItem is no longer uploading by setting uploadRequest to nil.
  4. Reloads the corresponding cell to reflect the request’s state changes.
  5. Sets GalleryItem.uploadRequest with uploadRequest. This indicates the running UploadRequest for this GalleryItem.

Next, you’ll upload a specific GalleryItem when the user taps an ImageCollectionViewCell.

So, add the following to ImagesCollectionViewController inside collectionView(_:didSelectItemAt:):

The code above calls upload(_:at:) for the selected GalleryItem and IndexPath if there’s no UploadRequest already running for this GalleryItem.

Before you run you need to display both the state and progress properties of this UploadRequest.

Reflecting the Upload Request State

Get to know the different Request states before you dive deeper into the code:

A Request starts in the Initialized state. It can be Suspended, Resumed, and Cancelled by calling the appropriate method. For example, resume() resumes or starts a Request, and suspend() suspends or pauses a request.

The resumed Request reaches the Finished state once all response validators and serializers have been run. However, if additional response serializers are added to this Request after that. It’ll transition back to the Resumed state and perform the network request again.

Note: If startRequestsImmediately is true, Alamofire calls resume() once a response handler is added to the Request.

Now, you’re ready to map these different states.

Open ImageCollectionViewCell.swift, add the following code inside the extension below // MARK: — UploadRequest:

This method reflects the UploadRequest states to the cell state.

Then, monitor the upload request progress. Add the following method below updateCellState(with:):

The code above:

  1. Sets the current progress of uploadRequest to the cell progressBar.
  2. Adds uploadProgress(queue:closure:) handler to uploadRequest for progress monitoring. It calls closure periodically with the progress of the sent data to the server.

Finally, combine these two methods to configure the cell.

Add the following to configureWithUploadRequest(_:):

All is ready. Build and run. Tap on an image.

Small owl says: Authentication required, again!!

Ooh! You didn’t add ImagesRequestInterceptor to the UploadRequest.

Before you add it, Session has another suggestion!

Creating Images Session

Alamofire’s Session provides APIs for the various Request subclasses. Furthermore, it encapsulates a variety of configurations applied to its requests.

Session provides a default singleton instance which is used by the AF namespace. AF.request(“https://...") is equivalent to Session.default.request(“https://...").

All Imgur requests require you to inject an ImagesRequestInterceptor into their cycle.

Under Sessions group, create a new Swift file named ImagesSession.swift.

Add the following to the file:

This code creates a default singleton instance for ImagesSession. It customizes the Session by assigning an ImagesRequestInterceptor instance to its interceptor.

Note: For more Session configurations, check the Alamofire Documentation.

Now, head back to ImagesCollectionViewController.swift and apply the following changes:

  • In fetchImages(), replace AF.request with ImagesSession.default.request.
  • In upload(_:at:), replace AF.upload with ImagesSession.default.upload.

Build and run. Upload an image. Check your Imgur profile.

Green progress bar accelerating when select an image then disappear

Pausing & Resuming the Upload Request

Controlling the uploading state is a nice gift to the user. :]

While you’re still in ImagesCollectionViewController.swift, add the following code below // MARK: — Alamofire Request:

It adds suspendOrResume() to toggle the state of Request between suspended and resumed.

To pause and resume the uploading when the user taps an ImageCollectionViewCell, add the following code below
// TODO: Suspend or resume request:

This reverses the UploadRequest state for the already uploading cell.

Build and run.

Green progress bar accelerating when select an image then stop when tap then resume to disappear when tap again

Listening for Internet Reachability

Listening to the network reachability status is useful. However, don’t use it to determine if you should send a network request.

Alamofire provides NetworkReachabilityManager for such scenarios. It listens for changes in the reachability of hosts and addresses.

Now, you’ll discover how to use it and display the reachability status.

Open MonstersTableViewController.swift. Add the following property to MonstersTableViewController:

Then, add the following extension below // MARK: — Network Reachability:

Here, the code:

1. Initializes MonstersTableViewController.reachabilityManager with Apple host. You can pass any trusted live host to listen.
2. Then, it calls startListening(onQueue:onUpdatePerforming:) to start tracking the changes of network reachability status.
3. Next, it reflects the reachability status to the UINavigationBar prompt.
4. The first fetchMonsters() call in viewDidLoad() may fail for any reason. Here’s a suitable place to fetch the data once the status becomes reachable.

Finally, add listenToReachability() to the bottom of viewDidLoad() to start listening.

Note: It’s better to use an iOS device rather than the simulator. When running in the simulator and toggling WiFi off, then back on, that the reachability APIs do not report that connectivity was restored due to the runtime behavior of the simulator.

Build and run. Turn off your internet connection to see the status changes.

Navigation bar prompt text changing with the reachability status changes
honored swift icon says: Enjoy DnDRealm app!

Conclusion

You can download the final project from the repository below. In this tutorial, you’ve learned Alamofire advanced techniques to deal with different aspects as routing, and authentication cycle. You also learned about using different Request types.

To learn more about behind the scene details, check out URLSession Getting Started tutorial. It’s a great jumping-off point for URLSession requests. If you have any questions or comments on this tutorial, please join the discussion below!

Acknowledge

Special thanks for raywenderlich.com for supervising and guidance.

--

--

Amr El-Sayed
Mac O’Clock

Amr is an iOS team lead, granted his Master’s degree in Mobile Cloud Computing. He is excited about learning and sharing new concepts. LN: /in/amrelsayedmohamed