Alamofire Tutorial for iOS: Advanced Usage

In this tutorial, you’ll learn about the advanced usage of Alamofire. Topics include handling OAuth, network logging, reachability, caching and more. By Vidhur Voora.

5 (23) · 3 Reviews

Download materials
Save for later
Share
You are currently viewing page 3 of 3 of this article. Click here to view the first page.

Routing Requests and URLRequestConvertible

So far, when making a network request, you've provided the URL path, HTTP method and query parameters for each request. As the app size grows, it's essential to use some common patterns for building the network stack. A Router design pattern helps by defining each request's route and components.

In Networking, open GitRouter.swift. You'll see all the requests you've made so far, captured as different cases in the enum. Use this GitRouter to construct your requests.

Add the following extension to the end of GitRouter.swift:

//1
extension GitRouter: URLRequestConvertible {
  func asURLRequest() throws -> URLRequest {
    //2
    let url = try baseURL.asURL().appendingPathComponent(path)
    var request = URLRequest(url: url)
    request.method = method
    //3
    if method == .get {
      request = try URLEncodedFormParameterEncoder()
        .encode(parameters, into: request)
    } else if method == .post {
      request = try JSONParameterEncoder().encode(parameters, into: request)
      request.setValue("application/json", forHTTPHeaderField: "Accept")
    }
    return request
  }
}

Here's a breakdown:

  1. You add an extension to GitRouter to conform to URLRequestConvertible. The protocol has a single requirement, asURLRequest(), which helps construct a URLRequest. Conforming to URLRequestConvertible helps abstract and ensure the consistency of requested endpoints.
  2. Here, you construct the request using the properties in GitRouter.
  3. Based on the HTTP method, you encode the parameters using either URLEncodedFormParameterEncoder or JSONParameterEncoder. The Accept HTTP header is set for POST request. You return the request after constructing it.

Now, open GitAPIManager.swift. You'll update all the request methods to use GitRouter.

In fetchCommits(for:completion:), delete the line that begins let url =. Now, replace sessionManager.request(url) with the following to use your new router:

sessionManager.request(GitRouter.fetchCommits(repository))

In searchRepositories(query:completion:), delete everything before sessionManager.request.... Now, replace sessionManager.request(url, parameters: queryParameters) with:

sessionManager.request(GitRouter.searchRepositories(query))

Likewise, in fetchAccessToken(accessCode:completion:), delete everything before sessionManager.request.... Now, replace the sessionManager.request(...) call with:

sessionManager.request(GitRouter.fetchAccessToken(accessCode))

Finally, in fetchUserRepositories(completion:), delete everything before sessionManager.request(url, parameters: parameters) and replace that line with:

sessionManager.request(GitRouter.fetchUserRepositories)

You remove the URL, query parameters and headers declared locally in each of these methods since you no longer need them. GitRouter constructs URLRequests for each request. Build and run.

Logged in user repositories

You'll see your repositories load as before except the underlying requests use GitRouter.

So far, the app works well. With a good network, the results are almost instantaneous. But the network is one unpredictable beast.

It's important to know when the network isn't reachable and inform the user in your app. Alamofire's NetworkReachabilityManager at your service!

Network Reachability

In the Networking group, open GitNetworkReachability.swift. Add the following just before the closing brace:

// 1
let reachabilityManager = NetworkReachabilityManager(host: "www.google.com")
// 2
func startNetworkMonitoring() {
  reachabilityManager?.startListening { status in
    switch status {
    case .notReachable:
      self.showOfflineAlert()
    case .reachable(.cellular):
      self.dismissOfflineAlert()
    case .reachable(.ethernetOrWiFi):
      self.dismissOfflineAlert()
    case .unknown:
      print("Unknown network state")
    }
  }
}

GitNetworkReachability provides a shared instance. It includes the functionality to show and dismiss an alert. Here's what you added:

  1. Alamofire's NetworkReachabilityManager listens for the reachability of hosts and addresses. It works on both cellular and WiFi network interfaces. Here, you create a property, reachabilityManager, as an instance of NetworkReachabilityManager. This checks for reachability using www.google.com as the host.
  2. startNetworkMonitoring() listens for changes in the network reachability status. If the network isn't reachable, an alert is displayed. Once there's a network that's reachable through any of the network interfaces, the alert is dismissed.

Now, open AppDelegate.swift. Add the following in application(_:didFinishLaunchingWithOptions:) right before return true:

GitNetworkReachability.shared.startNetworkMonitoring()

Here, you call startNetworkMonitoring() on GitNetworkReachability to start listening for network reachability status when the app launches.

Build and run. Once the app launches, turn the network off.

Network reachability on Alamofire

The app shows the user an alert when the network isn't reachable and dismisses it when it's reachable. Great job being user-centric!

Note: You should test functionality related to network reachability on a real device because reachability might not work as expected on a simulator. You can learn more about the issue by reading this GitHub post.

Sometimes showing an alert isn't the ideal experience. Instead, you might prefer showing previously fetched app data when there's no network. Alamofire's ResponseCacher is here to help. :]

Caching Using ResponseCacher

Open GitAPIManager.swift. Remove the following configuration options in sessionManager:

configuration.timeoutIntervalForRequest = 30
configuration.waitsForConnectivity = true

Here, you remove the timeoutIntervalForRequest and waitsForConnectivity configuration options so the app doesn't wait for network connectivity.

Add the following below let configuration = URLSessionConfiguration.af.default in sessionManager:

//1
configuration.requestCachePolicy = .returnCacheDataElseLoad
//2
let responseCacher = ResponseCacher(behavior: .modify { _, response in
  let userInfo = ["date": Date()]
  return CachedURLResponse(
    response: response.response,
    data: response.data,
    userInfo: userInfo,
    storagePolicy: .allowed)
})

Here's a breakdown:

  1. To cache requests for the session, you set requestCachePolicy on URLSessionConfiguration to returnCacheDataElseLoad. Once set, the cache returns the response. If the cache doesn't have a response, a network request is made.
  2. Alamofire's ResponseCacher makes it easy to specify whether a request needs to get cached, not cached or modified before storing in the cache. Here you modify the response by specifying .modify, before saving into the cache. You save the response's date, in addition to the content of the response, by passing it in the userInfo dictionary.

Now update Session initialization in sessionManager as below:

return Session(
  configuration: configuration,
  interceptor: interceptor,
  cachedResponseHandler: responseCacher,
  eventMonitors: [networkLogger])

Here you pass responseCacher as cachedResponseHandler in the constructor of Session. This makes responseCacher handle the caching behavior for all the requests in Session.

Open AppDelegate.swift. Comment out the following line of code which starts network monitoring:

GitNetworkReachability.shared.startNetworkMonitoring()

This prevents the app from showing the No Network alert when it's offline. Turn off network access on the simulator or device. Build and run.

Logged in user repositories

Ta-da! You'll see the repositories loaded from the cache.

Congratulations! You're now an Alamofire pro. :]

Where to Go From Here?

Download the final project by clicking the Download Materials button at the top or bottom of the tutorial.

In this Alamofire tutorial, you learned how to:

  • Create a custom Session and URLSessionConfiguration.
  • Log network requests and responses using EventMonitor.
  • Handle authentication and retries using RequestInterceptor.
  • Configure a Router with URLRequestConvertible.
  • Check for network reachability using NetworkReachabilityManager.
  • Modify responses before caching using ResponseCacher.

To learn more, please check the Alamofire advanced usage documentation.

I hope you enjoyed this tutorial. If you have any questions or comments, please join the forum discussion below.