In my app delegate I create a data model and inject it into a root view controller I got from a storyboard while requesting user's credentials if needed from the start. At some point later, when accessing some data model methods, I would need to verify a user’s password and retry a request that triggered password's re-verification.
Most obvious is to build in this functionality into each view controller that may need to request this information, but I want to avoid this as much as possible because it makes controllers less generic, also makes testing harder. In my mind controllers mustn’t know anything about inner workings of the model they're given.
Adding this functionality to the model also doesn’t feels right for me: managing user interaction is all beyond responsibilities of a model in MVC.
Who should be responsible for showing a modal dialog with corresponding view controller to let a user input his credentials?
You create a modal dialog box by using the DialogBox function. You must specify the identifier or name of a dialog box template resource and a pointer to the dialog box procedure. The DialogBox function loads the template, displays the dialog box, and processes all user input until the user closes the dialog box.
Dialog (dialogue): A conversation between two people. In a user interface, a dialog is a “conversation” between the system and the user. Mode: A special state of the system in which the same system has somewhat different user interfaces.
In contrast, nonmodal (or modeless) dialogs and windows do not disable the main content: showing the dialog box doesn't change the functionality of the user interface. The user can continue interacting with the main content (and perhaps even move the window, minimize it, etc.) while the dialog is open.
aria-modal is meant to indicate to screen readers that only content contained within a dialog with aria-modal="true" should be accessible to the user. This attribute is a pretty big deal and a very welcome addition to the specification.
It could be done using very few lines of code via callbacks. The callback API would be defined at the model layer (so it's reusable), but the user interaction is implemented at the controller level (because that's where it belongs).
I'm not entirely sure what your architecture exactly looks like, based on your description, I assume the app realizes you're not authenticated only on a failed request (you might want to store your token expiration date and leverage it, if possible).
Basic idea:
In your model, you have a callback block property (e.g. on a client class or whatever other pattern you use).
@property (nonatomic, copy) void (^onNonauthenticatedRequest)(NSURLRequest *failedRequest, NSError *error);
You execute this block in the model layer when your request fails due to the user not being authenticated.
On the controller level,you have a controller that prompts the user for credentials (and has a similar callback pattern).
client.onNonauthenticatedRequest = ^(NSURLRequest *failedRequest, NSError *error) {
ABCredentialsViewController *credentialsViewController = [ABCredentialsViewController new];
credentialsViewController.onAuthenticationSuccess = ^{
// This gets called after the authentication request succeeded
// You want to refire failedRequest here
// Make sure you use a weak reference when using the object that owns onAuthenticationFailure
};
credentialsViewController.onAuthenticationFailure = ^(NSError *) {
// You might want to do something if the user is not authenticated and failed to provide credentials
}
[[UIApplication sharedApplication].delegate.window.topViewController presentViewController:credentialsViewController animated:YES];
// or you could just have a method on UIViewController/your subclass to present the credentials prompt instead
};
The logic is in the correct place and if you want to handle non-authenticated requests differently in a different case, you can.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With