I'm writing an iPhone app that interacts with a web service1. By necessity, that creates a lot of delayed interactions; situations where the user interacts with the app, the app contacts the server, the server responds, and the app shows the result with a noticeable delay. This delay creates room for strange situations. If the user selects an entry in a table view and the app doesn't react immediately, the user may think that something went wrong and try to select a different entry. The same issue can be observed in web browsers where users repeatedly click on the same link, thinking the computer has not registered their first click if it doesn't react immediately.
To make sure that my app does not behave in unexpected ways, I've looked into how other apps solve this problem. The following example is from a very cool Google Analytics client, conceptually similar to my own app. In this screenshot, I've touched "Today". The app responds by highlighting "Today", blocking all user interaction, and throwing up an activity indicator - a spinning wheel - to show that the app is working:
This clearly solves the problem. The user can't select any of the entries while the app is interacting with the server, thus no unexpected situations can occur. However, blocking all user interaction means that there is no way to cancel the current action. What if I actually wanted to select "Dashboard" instead? What if the interaction takes too long and I want to do something else? The app won't let me do that.
Not being able to interact with an app can be a frustrating experience.
In order to avoid blocking user interaction in my own app whenever possible, I've decided to show the new screen immediately after the user selects an entry. At first, the new screen will be empty, except for the "back" button. Again, an activity indicator is shown, but this time, there is no need to block user interaction since this screen has no existing state that could create unexpected situations if the user interacts with it:
If the user grows bored with waiting or remembers that he selected the wrong item, he can simply select the "back" button to go back to the previous screen. This will essentially cancel the user's previous action and remove the current screen entirely, thus avoiding any problematic situations.
Apple uses the same "load an empty screen immediately, then load the data asynchronously" model. It should be noted that they don't use a "naked" UIActivityIndicatorView though. Instead, they add a small "Loading..." text. It's probably a good idea to follow Apple's lead and mimic this behaviour:
Whenever you find yourself blocking all user interaction, think about how you can avoid doing this. Sometimes it can't be helped, but often, there's a better way.
No, it's not the billionth iPhone Twitter client, it's a FogBugz client. ↩︎
If you require a short url to link to this article, please use http://ignco.de/119