Under The Bridge Under The Bridge

Tag: api
Offline Networking Management

So we have this new app that synchronizes all its operations with the website backend; and what, what, we ask rhetorically, do you figure the immediate cacophony of demand is?

Why, yes. Yes, it’s “Make checking in work offline!” Of course it is.

Now, 1.0 does cache all the last retrieved data so we’ve made a start on offline operation…

The Many Offline Options for iOS Apps

How to Design Offline-first Approach in a Mobile App

… so in this context, “work offline” is going to be defined as “queue database transactions to be applied to the server once connectivity is established,” as opposed to the current strategy of “call the API and do nothing if it fails”. We’re going to break that into a series of steps:

1) Currently our database transactions are UI state driven, with local changes applied only after online success, with a modal dialog forcing the user to wait. This is expedient, but annoying, and fallible.

So what we’ll do is encapsulate all our transactions into undoable objects, apply them to the local database immediately, and queue them for retry or cancel, ie. undo, if the online synchronization fails. Since having a functioning Undo implementation is a fine idea in any case, and helps us abstract out this rearchitecting nicely. If like us you haven’t implemented Undo recently (like in Swift at all) here’s some good tips on that:

Adding Undo and Redo support to iOS

UndoManager Tutorial: How to Implement With Swift Value Types

2) We’re going to need some awareness of when connectivity is established, to trigger applying these transactions to the server. Alamofire our networking layer has a simple one, implemented like thousands of others on top of ancient code. However, it has its issues … and there is a better option these days (iOS 12+): NWPathMonitor

Network Framework in iOS: How to Monitor Network Status Changes with sample code

Detecting Internet Access on iOS 12+ … now supported in Connectivity along with Solving the Captive Portal Problem. And backwards compatible Reachability support. So that looks like an excellent choice for network awareness needs!

And as an aside here, if you want to prompt people who turn off your app’s mobile data to turn it back on, check out

Handle disabled mobile data setting on iOS

However, for this particular application we can see that being a popular setting seeing as it’s all about foreign travel and all, so we’re not going to fuss about it as only working on wifi would be very likely indeed to be the users’ preferred mode of operation.

Speaking of operations, that brings us to:

3) A serializable and resumable and retryable queue for managing these operations

Right now we have a pretty simple asynchronous Operation wrapper for simple serial queuing of background data refresh operations, not completely unlike the network Operations described here,

Building a Networking Layer with Operations

Download files sequentially using URLSession inside OperationQueue

and as mentioned in the first point we’ll be making their local transactions undoable; but we’re going to need something a little more high powered than a stock memory OperationQueue to handle these, won’t we? Well, there are a number of possibilities mentioned that have various levels of support for persistence and awareness mentioned over in that promises roundup we did long before Combine was on the horizon, but here is one of particular interest:

OfflineRequestManager: Pod for Offline Network Request Management

OfflineRequestManager is a Swift framework for ensuring that network requests are sent even if the device is offline or the app is terminated.

OfflineRequestManager works by enqueuing OfflineRequest objects wrapping the network request being performed and observering the current network reachability using Alamofire. If the app is already online, then it will be performed immediately…

…! If a network-related error is passed into the completion block, then the OfflineRequestManager will retain the request and try again later. Other errors will by default remove the request from the queue, but there are optional delegate methods to allow for adjustment and resubmission if needed.

Realistically, there will likely be some data associated with the request. You also may want to be sure that the request is sent up even if the app is quit or (heaven forbid!) crashes…

Well, that would be … pretty much our exact feature requirements, actually! Hasn’t been updated in a year from Swift 4.0, so we’ll reimplement it in Swift 5.1 and add NWPathMonitor savviness and all, but a modernization is quite a less imposing task than designing from scratch, yes?

… and as a stretch goal, we’ll see about it taking advantage of background tasks too. You check out that new framework?

Managing background tasks with the new Task Scheduler in iOS 13

How to use BackgroundTasks framework to keep your iOS app content up to date?

So definitely, a superlatively up to date network request manager would also take advantage of that for recurring tasks!