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
is equivalent to obj-c Blocks)
void GetLatestNews(GetLatestRequest request, Action success, Action error)
void Search(SearchRequest request, Action success, Action 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 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.