You're right. The construction of this function in view controllers is not necessary and poor encapsulation.
In the MVC paradigm, models often have a data context. Data contexts control communication with the backend repository (in iOS, it is usually a web service or a local file) to populate and archive model objects. For an authenticated Data Context, you have a property for username, password, and authentication status.
@interface DataContext : NSObject //Authentication @property (nonatomic, strong) NSString * username; @property (nonatomic, strong) NSString * password; @property (nonatomic, assign) NSInteger authenticationState; -(void)login; //Data object methods from authenticated data source (web service, etc) -(NSArray *)foos; -(NSArray *)bars; @end
The authenticated state can be simple logical or integer if you want to monitor many states (authenticated, not authenticated, not authenticated after trying to authenticate with the credentials stored). Now you can observe the authenticationState property so that your controller level can take action when the authentication state changes.
When requesting data from a web service, you change the authentication state when the server refuses the request due to invalid credentials
-(NSArray *)foos { NSArray * foos = nil;
The controller is your application delegate. It stores an instance of our DataContext. It tracks changes to this authenticated property and displays a view or re-authentication when necessary.
- (void)observeAuthenticatedState:(NSNotification *)notification { DataContext * context = [notification object]; if (context.authenticatedState == 0)//You should have constants for state values if using NSIntegers. Assume 0 = unauthenticated. { [self.context login]; } if (context.authenticatedState == -1)//You should have constants for state values if using NSIntegers. Assume -1 = unauthenticated after attempting authentication with stored credentials { UIViewController * loginController = nil;//Instantiate or use existing view controller to display username/password to user. [[[self window] rootViewController] presentViewController:loginController animated:YES completion:nil]; } if (context.authenticatedState == 1)//authenticated. { [[[self window] rootViewController] dismissViewControllerAnimated:YES completion:nil]; } }
In your storyboard, you can basically pretend that authentication does not exist, because your application delegate inserts a user interface for authentication whenever the data context communicates with it.