My approach is similar to your '(2) At the API request level' - except rather than encapsualting the request in an object, encapsulate the whole concept of the API server.
Therefor I usually end up wrapping each type of request with an async method signature like this:
(Sorry, its C#, not obj-c (I use Xamarin.iOS) but the concept is the same - Action<T>
is equivalent to obj-c Blocks)
void GetLatestNews(GetLatestRequest request, Action<NewsListingResponse> success, Action<Exception> error)
void Search(SearchRequest request, Action<SearchResponse> success, Action<Exception> error)
I usually just make these static methods on a static class (very rarely will there be more than 1 server of the same type so a single static class will work fine) but I do sometimes put them within a singleton instance class so that I can pass in a mocked instance for unit tests.
Anyway, now your VC client code just consumes the api as needed:
override void ViewDidAppear(bool animated)
{
SomeNewsSiteApi.GetLatestNews( new GetLatestRequest{Count=20},
response =>
{
// Update table view here
},
error =>
{
// Show some error alert
});
}
The beauty of this is that the implementation of those methods handle sending the request with the current token, and if it fails, obtains a new token, and then resends the same request with the new token, only then finally calling back into the Action<T> success
callback. The client VC code has no idea about any re-obtaining of tokens, all it knows and cares about is that it is making a request for some data, and waiting for either a response or an error.