After developing for iOS for some time now, I have gotten comfortable with the language and am trying to get better at designing well-structured applications. Initially my focus was on seeing something functional, so I ended up with gigantic view controllers which were horribly architected. Now, I’m learning to separate my model classes and trying to keep my architecture more modular. I would greatly appreciate any advice on the following sample situation:
I am developing an app which (among other things) pulls a list of articles from a server and displays them. However, the user has to be authenticated to be able to retrieve this list. Because other aspects of the application utilize the same authentication, I want a single class to manage the authentication. The goal is that when any controller requests data from the model which requires authentication, if the user is not authenticated, the authentication prompt will automatically be presented.
I expect to create the following:
VIEW
– ArticlesView
– AuthenticationView
CONTROLLER
– ArticlesViewController
– AuthenticationViewController
– ArticleManager (singleton)
– AuthenticationProvider (singleton)
MODEL
– Article
When the application first loads, execution will reach the ArticlesViewController’s viewDidLoad method. In this method, I get a shared instance of the ArticleManager, specify the authentication class to be the authentication provider, and ask it for a list of recent articles.
// ArticlesViewController.m
-(void) viewDidLoad {
...
AuthenticationProvider *authProvider = [AuthenticationProvider sharedInstance];
[[ArticleManager sharedInstance] setAuthenticationProvider:authProvider];
[[ArticleManager sharedInstance] fetchNewArticles];
}
If no authentication was necessary, the ArticleManager would successfully retrieve the list from the server and post a notification letting anyone interested know that the articles have been retrieved. The ArticlesViewController would handle this notification:
// ArticlesViewController.m
- (void) handleNewArticlesNotification:(NSNotification *)note {
[self updateUI];
}
However, if authentication is required, the user needs to be presented with a login screen before the articles can be fetched and displayed. So I imagine the ArticleManager doing something like this:
// ArticleManager.m
- (void) fetchNewArticles {
if( [self.authenticationProvider isAuthenticated] ){
// go fetch list from the web
}
else {
[self.authenticationProvider presentAuthenticationRequest];
}
}
Now, at this point I run into some difficulty fleshing out the remainder of the details. The AuthenticationProvider could present the AuthenticationViewController as a modal view controller from the AppDelegate’s window’s rootViewController and AuthenticationProvider would be the delegate of AuthenticationViewController. The AuthenticationViewController would probably be dumb to the actual actions that it is taking, and would have it’s delegate (AuthenticationProvider) do the work to authenticate the user. Once the user is authenticated, AuthenticationProvider would dismiss the modal view controller (AuthenticationViewController).
But how does ArticleManager get notified that the authentication that it requested has completed? It would need to be able to handle both successful and failed authentication attempts separately. A successful authentication would eventually result in fetchNewArticles being called again.
One thought is for ArticleManager to be a delegate of AuthenticationProvider. This seems to work in this case, but there are other Model Managers which could also rely on AuthenticationProvider. Presumably this would be resolved if AuthenticationProvider is not a singleton. Would that be a decent design approach?
Thanks for taking the time to help me understand a good design approach. I have coded this a couple of times, but always get stuck/confused toward the end. Also, if the entire approach needs to be re-architected, please feel free to point me in another direction.
Many thanks!
I have always used Global NSNotifications to post when a user has logged in or logged out. Every view controller that presents data differently can subscribe to those notifications and update themselves accordingly when an event happens.
This is nice, because you may already have other views (perhaps in other tabs) that have already loaded and will need to refresh when a user has logged in or out.