Tag Archives: ipad

Handling Bad Connectivity with AFNetworking 2

I’ve been a web developer for the past ten years. There’ve always been plenty of challenges for me while creating websites – some I’ve handled better than others. I’ve run into file submission security issues, handling vast amounts of downloads, terrible web designs, hardening servers and more. There’s one thing I never had to contemplate until I started developing mobile applications: bad connectivity issues.

With DohGames, if a user ever had an issue connecting to the site or the download, I could just chalk it up to an internet issue or some faulty setting on their router (AKA, not my concern). The vast majority of the time though, a user’s connection would be reliable enough and out of my realm of control. A simple refresh to the page, or the clicking of the button again would fix the problem.

With mobile apps, it’s a different story.

Bad Connectivity Issues Abound

Your users are out and about. They could be traveling in a car, underground, in the middle of nowheresville USA or in a super crowded city with millions of users all fighting for their connections. Connections will be dropped or a lot slower than they should be in 2014. It sucks but you have to handle it unless you want a poorly rated application.

While I don’t feel like I could sufficiently discuss the various design decisions on how to handle this all (I’m a developer, not a designer for good reason), I did run across this while working and had to implement what we felt would work best for our app.

AFNetworking to the Rescue

afnetworking-logo bad connectivity tutorial

I recently upgraded our networking code to utilize AFNetworking 2. We were previously using a completely handmade solution that was unreliable, clunky and full of boilerplate code that had to be copy and pasted every time you wanted to add a new request. It sucked.

A lot.

I could write plenty about AFNetworking (and hopefully will) so I’ll leave out all of the details BUT one of the added features of it, that I was completely unaware of at the time of making the switch, was the built in ability to handle bad connectivity issues with the AFNetworkReachabilityManager.

Every AFHttpRequestOperationManager has a ReachabilityManager associated with it. This ReachabilityManager then has a block called reachabilityStatusChangeBlock that is called whenever your device loses/gains connectivity. We can utilize this to our advantage!

The reachabilityStatusChangeBlock is called with a AFNetworkReachabilityStatus parameter which tells you’re the current state of your connection. Using this, we can tell our app to do whatever we want.

For example, inside your subclassed AFHttpRequestOperationManager (I do this inside my -(id)init), you can specify your block as follows:

[self.reachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status){
	switch (status) {
		case AFNetworkReachabilityStatusUnknown:
		case AFNetworkReachabilityStatusReachableViaWiFi:
		case AFNetworkReachabilityStatusReachableViaWWAN:
			// Our connection is fine
			// Resume our requests or do nothing
		case AFNetworkReachabilityStatusNotReachable:
			// We have no active connection - disable all requests and don’t let the user do anything
			// If we get here, we’re most likely timing out

// Set the reachabilityManager to actively wait for these events
[self.reachabilityManager startMonitoring];

AFNetworking (and I) would suggest you resume ([self.operationQueue setSuspended:NO]) the operationQueue on your AFHttpRequestOperationManager when your connection is OK or suspend it ([self.operationQueue setSuspended:YES]) when these events occur so that when the connection is fixed, any actions the user wanted to take will resume normally.

You can test this out once you’ve added it to your AFHttpRequestOperationManager by running your application, setting a breakpoint inside of that block, and toggling the AirplaneMode on your device/simulator.

What else?

That’s pretty useful in itself; however, there’s still a lot more to be accomplished with this code block! Notice how my final case in that switch statement mentions timeouts? What if the user just had a bad connection but is fine now? What if their connection is fine but your backend is running slowly? Do you reattempt? Do you completely disable the app? Let the user continue with no notification whatsoever?

This is where things can get tricky.  Let’s just say it involves implementing an attempt count as well as the ability to easily retry requests. But that’s for another day and article.