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.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Alamofire Tutorial for iOS: Advanced Usage
25 mins
- Getting Started
- Custom Session and URLSessionConfiguration
- Customizing Session
- Logging Network Requests and Responses Using Event Monitor
- GitHub Authorization
- OAuth Overview
- Creating GitHub OAuth App
- Logging Into GitHub
- Fetching User Repositories
- Request Overview
- RequestInterceptor Overview
- Integrating RequestInterceptor
- Routing Requests and URLRequestConvertible
- Network Reachability
- Caching Using ResponseCacher
- Where to Go From Here?
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:
- You add an extension to
GitRouter
to conform toURLRequestConvertible
. The protocol has a single requirement,asURLRequest()
, which helps construct aURLRequest
. Conforming toURLRequestConvertible
helps abstract and ensure the consistency of requested endpoints. - Here, you construct the request using the properties in
GitRouter
. - Based on the HTTP method, you encode the parameters using either
URLEncodedFormParameterEncoder
orJSONParameterEncoder
. 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 URLRequest
s for each request. Build and run.
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:
- 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 ofNetworkReachabilityManager
. This checks for reachability using www.google.com as the host. -
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.
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!
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:
- To cache requests for the session, you set
requestCachePolicy
onURLSessionConfiguration
toreturnCacheDataElseLoad
. Once set, the cache returns the response. If the cache doesn't have a response, a network request is made. - 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 theuserInfo
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.
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.