Often, our daily challenges are solved with simple solutions instead of overly complex or “clever” ones that even the authors don’t understand a month later.
Not long ago (in a galaxy quite close to our own; okay, the same one), we ran into an issue where we needed to add activity indicators on some tableviews when getting information from a remote data source. At first, this seemed liked a simple case of showing the indicator when the call for data begins then hiding it in the completion handler when the data is returned.
We soon noticed that there were times when the activity indicator was being hidden while a search was still executing. The only code to hide the indicator was in the completion handler so, at first, it was puzzling.
The application’s data access layer often allows that a request for data be “cancellable.” There are times when a request might be in flight (e.g., an initial call for data when the tableview appears) and a user may tap into the search bar and start filtering by keying characters before a previous search has completed. When that happens, the previous search is cancelled, but the completion handler from that search still gets called.
As hiding of the activity indicator takes place in the completion block, this would occur even though another request was still being executed. We needed to prevent the indicator from being hidden until the last request was finished and ignore the other callbacks that would have hidden it prematurely.
Our first thought was to have an ivar that could be incremented when searches were made then decremented in the completion handler. When it reached zero, that would indicate that the last executing search had finished and then, and only then, would hiding of the indicator take place. It was a simple solution and worked as expected.
After considering the number of places this would be useful, we decided to create a struct that exposes two methods:
An internal counter goes up and down with calls to the corresponding method, and false is only ever returned if the value is zero.
Now, when a search is started, the increment method is invoked on the counter and the flag indicating that an update is occurring is set just prior to the call for data:
When the completion handler is called, the decrementWithValue() method is called on our counter and its result assigned to the flag (which also hides the activity indicator):
Now, if a search is cancelled for whatever reason and another search is still executing, the completion handler is still called, but the activity indicator remains visible.
This solution eliminated the need to go deeper into the data access layer and attempt a modification that may have resulted in unexpected behaviors and side effects.
At times, it’s tempting to create “clever” or “elegant” solutions to problems we’re dealing with. And sometimes, those are the things to do. But it’s also valuable to consider the “keep things simple” principle when you’re writing code. Your team (and maybe, your future self!) will appreciate it.